Messages

Messages are individual WhatsApp messages within a conversation. See Database Schema for the full column reference.

List Messages

const { data } = await sendhub
  .from('messages')
  .select('id, direction, sender_type, content, delivery_status, confidence, is_draft, created_at')
  .eq('conversation_id', convoId)
  .order('created_at', { ascending: true })

Send a Message

const { data, error } = await sendhub.from('messages').insert({
  conversation_id: convoId,
  business_id: workspaceId,
  org_id: orgId,
  direction: 'outbound',
  sender_type: 'agent',
  content: 'Your order has shipped!',
}).select('id').single()

For personal (bridge) channels, message delivery is handled automatically through the WhatsApp bridge.

Search Messages

Full-text search across all message content in a workspace:

const { data } = await sendhub
  .from('messages')
  .select('id, conversation_id, content, sender_type, created_at')
  .eq('org_id', orgId)
  .ilike('content', `%${query}%`)
  .order('created_at', { ascending: false })
  .limit(50)

Subscribe to New Messages

const channel = sendhub
  .channel('inbox')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'messages',
    filter: `conversation_id=eq.${convoId}`,
  }, (payload) => {
    console.log('New message:', payload.new)
  })
  .subscribe()

// Also track delivery status changes
sendhub
  .channel('delivery')
  .on('postgres_changes', {
    event: 'UPDATE',
    schema: 'public',
    table: 'messages',
    filter: `conversation_id=eq.${convoId}`,
  }, (payload) => {
    console.log('Status:', payload.new.delivery_status)
  })
  .subscribe()

Delivery Status Flow

pending โ†’ sending โ†’ sent โ†’ delivered โ†’ read
                  โ†˜ failed (retryable)

AI Drafts

When AI confidence is below the channelโ€™s threshold, messages are saved as drafts:

// List drafts awaiting review
const { data: drafts } = await sendhub
  .from('messages')
  .select('id, content, confidence, created_at')
  .eq('is_draft', true)
  .eq('business_id', workspaceId)

// Approve and send a draft
await sendhub
  .from('messages')
  .update({ is_draft: false, delivery_status: 'sending' })
  .eq('id', draftId)

// Discard a draft
await sendhub
  .from('messages')
  .delete()
  .eq('id', draftId)