Messages API

Full CRUD for messages within channels, plus threads, reactions, file uploads, and AI-powered summarization. All endpoints require JWT authentication and are rate-limited to 60 requests per minute.

Base path: /api/v2/messages

Create Message

Create a new message in a channel. The message is validated, inserted into the database, broadcast to all channel members via WebSocket, and forwarded to any assigned digital twins.

POST/api/v2/messagesAuthenticated

Create a new message in a channel and broadcast to all members.

Body Parameters

channel_idstringrequired

UUID of the channel to post in.

contentstringrequired

Message content. Supports markdown.

content_typestring
Default: text

Content type identifier.

parent_message_idstring

UUID of parent message for threading.

metadataobject

Arbitrary metadata object attached to the message.

attachmentsobject[]

Array of attachment objects.

conversation_idstring

UUID of the conversation context.

user_idstring

Explicit user ID. Falls back to JWT user.

ai_twin_idstring

UUID of an AI twin sending this message.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Deploy the staging environment and run integration tests.",
    400">class="text-emerald-400">"metadata": {
      400">class="text-emerald-400">"source": 400">class="text-emerald-400">"api",
      400">class="text-emerald-400">"priority": 400">class="text-emerald-400">"high"
    }
  }'

Response 201

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Deploy the staging environment and run integration tests.",
    400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"parent_message_id": null,
    400">class="text-emerald-400">"metadata": {
      400">class="text-emerald-400">"source": 400">class="text-emerald-400">"api",
      400">class="text-emerald-400">"priority": 400">class="text-emerald-400">"high"
    },
    400">class="text-emerald-400">"attachments": null,
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T15:10:22.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T15:10:22.000Z"
  },
  400">class="text-emerald-400">"meta": {
    400">class="text-emerald-400">"timestamp": 400">class="text-emerald-400">"2026-03-19T15:10:22.000Z"
  }
}

Send Message (Alias)

Alias for the create endpoint. Accepts the same body and returns the same response.

POST/api/v2/messages/sendAuthenticated

Alias for POST /api/v2/messages. Same body and response.

Body Parameters

channel_idstringrequired

UUID of the channel.

contentstringrequired

Message content.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/send \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Quick update: tests passed."
  }'

Response 201

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Quick update: tests passed.",
    400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T15:12:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T15:12:00.000Z"
  },
  400">class="text-emerald-400">"meta": {
    400">class="text-emerald-400">"timestamp": 400">class="text-emerald-400">"2026-03-19T15:12:00.000Z"
  }
}

List Messages

Retrieve message history for a channel with offset-based pagination. Messages are returned with LEFT JOIN data from user_profiles and reaction counts.

GET/api/v2/messages/historyAuthenticated

List messages in a channel with pagination. Includes user profiles and reactions.

Query Parameters

channel_idstringrequired

UUID of the channel to fetch messages from.

thread_idstring

Filter to messages in a specific thread.

limitinteger
Default: 50

Maximum number of messages to return.

offsetinteger
Default: 0

Number of messages to skip.

Request

cURL
400">curl -X 400">GET 400">class="text-emerald-400">"https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/history?channel_id=550e8400-e29b-41d4-a716-446655440000&limit=25&offset=0" \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": [
    {
      400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
      400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
      400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Can you analyze the Q1 marketing data?",
      400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
      400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      400">class="text-emerald-400">"display_name": 400">class="text-emerald-400">"Matty Squarzoni",
      400">class="text-emerald-400">"avatar_url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//storage.lvng.ai/avatars/a0eebc99.jpg",
      400">class="text-emerald-400">"reactions": [],
      400">class="text-emerald-400">"parent_message_id": null,
      400">class="text-emerald-400">"metadata": {},
      400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T14:30:00.000Z",
      400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T14:30:00.000Z"
    }
  ],
  400">class="text-emerald-400">"meta": {
    400">class="text-emerald-400">"total": 142,
    400">class="text-emerald-400">"page": 1,
    400">class="text-emerald-400">"limit": 25,
    400">class="text-emerald-400">"offset": 0
  }
}

Search Messages

Full-text search on message content. Optionally scope to a specific channel.

GET/api/v2/messages/searchAuthenticated

Full-text search across messages. Searches the content column.

Query Parameters

querystringrequired

Search term. Matched against messages.content.

channel_idstring

Scope search to a specific channel.

limitinteger

Maximum results to return.

Request

cURL
400">curl -X 400">GET 400">class="text-emerald-400">"https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/search?query=deployment&channel_id=550e8400-e29b-41d4-a716-446655440000" \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": [
    {
      400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
      400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
      400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Deploy the staging environment and run integration tests.",
      400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T15:10:22.000Z"
    }
  ],
  400">class="text-emerald-400">"meta": {
    400">class="text-emerald-400">"total": 1
  }
}

Get Message

Retrieve a single message by ID. Includes reaction count.

GET/api/v2/messages/:idAuthenticated

Get a single message by UUID. Includes reaction count.

Path Parameters

idstringrequired

UUID of the message.

Request

cURL
400">curl -X 400">GET https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Can you analyze the Q1 marketing data?",
    400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"parent_message_id": null,
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"reaction_count": 3,
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T14:30:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T14:30:00.000Z"
  },
  400">class="text-emerald-400">"meta": {}
}

Edit Message

Update the content of an existing message. Ownership is checked — only the original author can edit.

PUT/api/v2/messages/:idAuthenticated

Edit a message. Checks ownership before updating.

Path Parameters

idstringrequired

UUID of the message to edit.

Body Parameters

user_idstringrequired

UUID of the user making the edit. Must match original author.

contentstringrequired

Updated message content.

Request

cURL
400">curl -X 400">PUT https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Can you analyze the Q1 and Q2 marketing data?"
  }'

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Can you analyze the Q1 and Q2 marketing data?",
    400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T14:30:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T15:45:00.000Z"
  }
}

Delete Message

Soft-delete a message by setting its deleted_at timestamp. Admins can delete any message; regular users can only delete their own.

DELETE/api/v2/messages/:idAuthenticated

Soft delete a message. Sets deleted_at timestamp rather than removing the row.

Path Parameters

idstringrequired

UUID of the message to delete.

Query Parameters

user_idstringrequired

UUID of the user requesting deletion.

adminboolean

Set to true to bypass ownership check (requires admin role).

Request

cURL
400">curl -X 400">DELETE 400">class="text-emerald-400">"https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7?user_id=a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11" \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"deleted_at": 400">class="text-emerald-400">"2026-03-19T16:00:00.000Z"
  }
}

Pin Message

Pin a message within its channel. Broadcasts a WebSocket event to all channel members.

POST/api/v2/messages/:id/pinAuthenticated

Pin a message. Broadcasts pin event via WebSocket.

Path Parameters

idstringrequired

UUID of the message to pin.

Body Parameters

user_idstring

UUID of the user pinning. Falls back to JWT user.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7/pin \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Can you analyze the Q1 marketing data?",
    400">class="text-emerald-400">"metadata": {
      400">class="text-emerald-400">"pinned": true,
      400">class="text-emerald-400">"pinned_by": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      400">class="text-emerald-400">"pinned_at": 400">class="text-emerald-400">"2026-03-19T16:05:00.000Z"
    },
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T16:05:00.000Z"
  }
}

Toggle Reaction

Add or remove a reaction on a message. If the user already has the same emoji reaction, it is removed (toggle behavior).

POST/api/v2/messages/:id/reactAuthenticated

Toggle a reaction on a message. Adds if not present, removes if already exists.

Path Parameters

idstringrequired

UUID of the message to react to.

Body Parameters

user_idstringrequired

UUID of the user reacting.

emojistringrequired

Emoji string for the reaction (e.g. "thumbsup", "fire").

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7/react \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"emoji": 400">class="text-emerald-400">"thumbsup"
  }'

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"d4735e3a-265e-16d0-8b4b-b7bfa8e5b9e0",
    400">class="text-emerald-400">"message_id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"user_id": 400">class="text-emerald-400">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    400">class="text-emerald-400">"emoji": 400">class="text-emerald-400">"thumbsup",
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T16:10:00.000Z"
  },
  400">class="text-emerald-400">"meta": {}
}

Reply in Thread

Create a reply in a message thread. Sets parent_message_id to the target message, creating a threaded conversation.

POST/api/v2/messages/:id/threadAuthenticated

Reply in a thread. Creates a message with parent_message_id set to :id.

Path Parameters

idstringrequired

UUID of the parent message to reply to.

Body Parameters

contentstringrequired

Reply content.

content_typestring

Content type identifier.

user_idstring

UUID of the replying user. Falls back to JWT user.

ai_twin_idstring

UUID of an AI twin sending this reply.

metadataobject

Arbitrary metadata for the reply.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7/thread \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Here is the Q1 analysis you requested.",
    400">class="text-emerald-400">"ai_twin_id": 400">class="text-emerald-400">"b5b2c3d4-e5f6-7890-abcd-ef1234567890"
  }'

Response 201

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"id": 400">class="text-emerald-400">"e3b0c442-98fc-1c14-b39f-27bd3e8cd9a1",
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"content": 400">class="text-emerald-400">"Here is the Q1 analysis you requested.",
    400">class="text-emerald-400">"content_type": 400">class="text-emerald-400">"text",
    400">class="text-emerald-400">"user_id": null,
    400">class="text-emerald-400">"ai_twin_id": 400">class="text-emerald-400">"b5b2c3d4-e5f6-7890-abcd-ef1234567890",
    400">class="text-emerald-400">"parent_message_id": 400">class="text-emerald-400">"7c9e6679-7425-40de-944b-e07fc1f90ae7",
    400">class="text-emerald-400">"metadata": {},
    400">class="text-emerald-400">"created_at": 400">class="text-emerald-400">"2026-03-19T16:15:00.000Z",
    400">class="text-emerald-400">"updated_at": 400">class="text-emerald-400">"2026-03-19T16:15:00.000Z"
  }
}

Upload Files

Upload one or more files as multipart form data. Files are stored in Supabase Storage and returned with public URLs.

POST/api/v2/messages/uploadAuthenticated

Upload files via multipart form data. Stores in Supabase Storage.

Body Parameters

filesFile[]required

One or more files (multipart form field).

conversation_idstringrequired

UUID of the conversation to attach files to.

workspace_idstring

UUID of the workspace.

conversation_typestring

Type of conversation (e.g. channel, dm).

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/upload \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -F 400">class="text-emerald-400">"files=@report.pdf" \
  -F 400">class="text-emerald-400">"files=@chart.png" \
  -F 400">class="text-emerald-400">"conversation_id=550e8400-e29b-41d4-a716-446655440000"

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"files": [
      {
        400">class="text-emerald-400">"name": 400">class="text-emerald-400">"report.pdf",
        400">class="text-emerald-400">"url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//storage.lvng.ai/uploads/550e8400/report.pdf",
        400">class="text-emerald-400">"size": 245760,
        400">class="text-emerald-400">"400">type": 400">class="text-emerald-400">"application/pdf"
      },
      {
        400">class="text-emerald-400">"name": 400">class="text-emerald-400">"chart.png",
        400">class="text-emerald-400">"url": 400">class="text-emerald-400">"https:400">class="text-zinc-500">//storage.lvng.ai/uploads/550e8400/chart.png",
        400">class="text-emerald-400">"size": 89200,
        400">class="text-emerald-400">"400">type": 400">class="text-emerald-400">"image/png"
      }
    ],
    400">class="text-emerald-400">"conversation_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"conversation_type": 400">class="text-emerald-400">"channel"
  }
}

Summarize Conversation

Generate an AI summary of recent messages in a channel using Claude Haiku. Returns the summary text, message count covered, and time range.

POST/api/v2/messages/summarizeAuthenticated

Generate an AI summary of channel messages using Claude Haiku.

Body Parameters

channel_idstringrequired

UUID of the channel to summarize.

messageCountinteger

Number of recent messages to include. Defaults to all recent messages.

Request

cURL
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v2/messages/summarize \
  -H 400">class="text-emerald-400">"Authorization: Bearer YOUR_JWT_TOKEN" \
  -H 400">class="text-emerald-400">"Content-Type: application/json" \
  -d '{
    400">class="text-emerald-400">"channel_id": 400">class="text-emerald-400">"550e8400-e29b-41d4-a716-446655440000",
    400">class="text-emerald-400">"messageCount": 50
  }'

Response 200

{
  400">class="text-emerald-400">"success": true,
  400">class="text-emerald-400">"data": {
    400">class="text-emerald-400">"summary": 400">class="text-emerald-400">"The team discussed the Q1 marketing report and deployment plans. Key decisions: marketing budget will increase 15% for Q2 targeting enterprise accounts, staging deployment scheduled for Friday with full integration tests, and Slack notifications will be added to the CI/CD pipeline.",
    400">class="text-emerald-400">"messageCount": 47,
    400">class="text-emerald-400">"timeRange": {
      400">class="text-emerald-400">"400">from": 400">class="text-emerald-400">"2026-03-18T09:00:00.000Z",
      400">class="text-emerald-400">"to": 400">class="text-emerald-400">"2026-03-19T15:12:45.000Z"
    }
  }
}