Messages
2 API calls in this section.
Endpoints for managing messages within conversations.
Realtime frontend contract
Subscribe to Supabase Postgres Changes on schema
public, tablemessages, event:INSERTusing a valid authenticated user access token.The database delivers a message only when the JWT user has a
message_participantsrow for that message's conversation withleft_atequal to null.A user does not receive messages from conversations where they have no active participant row or where their participant row has
left_atset.Do not subscribe with the
anonrole; anonymous database access tomessagesandmessage_participantsis revoked.Do not use event
*for this listener. The app-wide listener must be INSERT-only.Message creation and participant changes continue through the authenticated Messaging API; frontend clients have read-only table access.
On each received INSERT, refetch
GET /messaging/conversations/unread-countonce and update the shared unread badge state used by every chat icon.
List Messages
/messaging/conversations/:conversationId/messagesRetrieves messages from a specific conversation with filtering and pagination options.
Authorization
Requires valid authentication token
Standard conversations: user must be a participant in the conversation OR be system admin
Support-ticket conversations: only the ticket customer, a configured tenant support user while support is enabled, or a system admin can list messages
Active participant membership alone does not grant driver access to a support-ticket conversation
Unauthorized support-ticket access returns HTTP 403 with
{"success":false,"message":"Insufficient Permissions"}
Response
Returns paginated list of messages with sender information
Updates participant's last read message automatically
Path parameters
| Parameter | Type | Description |
|---|---|---|
conversationIdRequired | string | UUID of the conversation Example: |
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_id | string | UUID of the tenant (required if not in auth token) Example: |
page | string | Page number for pagination (default: 1) Example: |
limit | string | Number of items per page (default: 20) Example: |
timestamp_range | string | Filter by message timestamp range (format: 2023-01-01T00:00:00Z,2023-01-02T00:00:00Z) |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/messaging/conversations/${CONVERSATIONID}/messages?tenant_id=${TENANT_ID}&page=1&limit=20×tamp_range=" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json"Response examples
1{2 "success": true,3 "messages": [4 {5 "id": "uuid",6 "conversation_id": "uuid",7 "sender_id": "uuid",8 "message_type": "text",9 "content": "Hello!",10 "content_url": null,11 "metadata": null,12 "sent_at": "2023-01-01T00:00:00Z",13 "delivered_status": {},14 "deleted_by": [],15 "parent_message_id": null,16 "sender": {17 "id": "uuid",18 "full_name": "John Doe",19 "email": "[email protected]",20 "avatar_url": "https://example.com/avatar.jpg"21 }22 }23 ],24 "page": 1,25 "limit": 20,26 "total": 127}Send Message
/messaging/conversations/:conversationId/messagesSends a new message to a conversation.
Authorization
Requires valid authentication token
Standard conversations: user must be an active participant
Support-ticket conversations: only the ticket customer, a configured/eligible support user, or a system admin can send
Active participant membership alone does not grant driver access to a support-ticket conversation
Unauthorized support-ticket access returns HTTP 403 with
{"success":false,"message":"Insufficient Permissions"}Conversation must be in 'active' status
Asynchronous Push Delivery
After the message commits, a database trigger invokes the notifications Edge Function.
OneSignal push is sent to active conversation participants except the sender.
Muted participants, participants with
notification_preferences.push=false, users withnotifications_enabled=false, and participants who left the conversation are excluded.No
notificationsrow is created for a chat message.Push failure does not roll back the message or change this endpoint's HTTP 201 response.
Push data contains
action=open_conversation,conversation_id,message_id, andsender_id.
Frontend Integration
Register the authenticated backend user UUID as the OneSignal
external_id.On push tap, handle
action=open_conversationand navigate usingconversation_id.If that conversation is already open, suppress the foreground push banner and continue using message Realtime.
Note
message_type=htmlis reserved for server-generated messages (e.g., support acknowledgements) and is rejected if sent by clients.
Path parameters
| Parameter | Type | Description |
|---|---|---|
conversationIdRequired | string | UUID of the conversation Example: |
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_id | string | UUID of the tenant (required if not in auth token) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
message_type | string | — |
content | string | — |
content_url | null | — |
metadata | null | — |
parent_message_id | null | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/messaging/conversations/${CONVERSATIONID}/messages?tenant_id=${TENANT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "message_type": "text",6 "content": "Hello!",7 "content_url": null,8 "metadata": null,9 "parent_message_id": null10}'Other request examples (1)
1{2 "message_type": "text" | "image" | "file" | "audio" | "video" | "location", // required3 "content": "string", // required for text messages4 "content_url": "string", // required for media messages (image, file, audio, video)5 "metadata": {}, // optional additional data6 "parent_message_id": "uuid" // optional - for threaded replies7}Response examples
1{2 "success": true,3 "message": {4 "id": "uuid",5 "conversation_id": "uuid",6 "sender_id": "uuid",7 "message_type": "text",8 "content": "Hello!",9 "content_url": null,10 "metadata": null,11 "sent_at": "2023-01-01T00:00:00Z",12 "delivered_status": {},13 "deleted_by": [],14 "parent_message_id": null,15 "sender": {16 "id": "uuid",17 "first_name": "John",18 "last_name": "Doe",19 "email": "[email protected]",20 "avatar_url": "https://example.com/avatar.jpg"21 }22 }23}