Amba

Messaging

In-app direct and group messaging between users, with typed errors and SDK examples.

Amba provides in-app messaging for direct and group conversations between users. Every endpoint returns a typed error envelope — no opaque 500s.

SDK example: 1:1 conversation

The common shape — two users, one conversation, a thread of messages:

import { Amba } from '@layers/amba-web';
 
// Create a 1:1 conversation between the signed-in user and another
// user. For `type: 'direct'` the call is idempotent — calling it
// again with the same other-participant returns the existing row.
const conversation = await Amba.messaging.createConversation({
  participant_ids: [otherUserId],
  type: 'direct',
});
 
// Send a message into that conversation
const message = await Amba.messaging.sendMessage(conversation.id, {
  body: 'hey, want to start a daily streak together?',
});
 
// List the user's conversations (renders an inbox / chat list)
const conversations = await Amba.messaging.getConversations();
for (const c of conversations) {
  console.log(c.id, c.last_message?.body);
}
 
// Page through messages in a conversation (renders the thread view)
const messages = await Amba.messaging.listMessages(conversation.id, {
  limit: 50,
});
 
// Mark the conversation as read once the user has scrolled the thread
await Amba.messaging.markRead(conversation.id);

The full messaging surface — createConversation, getConversations, listConversations, sendMessage, listMessages, markRead — ships in @layers/amba-web@1.0.3+, @layers/amba-node@1.0.3+, @layers/amba-react-native@2.1.0+, and @layers/amba-expo@2.1.0+.

Typed errors

Branch on error.code for actionable handling:

import { AmbaApiError } from '@layers/amba-web';
 
async function startConversation(otherUserId: string, firstMessage: string) {
  let conv;
  try {
    conv = await Amba.messaging.createConversation({
      participant_ids: [otherUserId],
      type: 'direct',
    });
  } catch (err) {
    if (err instanceof AmbaApiError) {
      if (err.code === 'USER_NOT_FOUND') {
        // One of the participant_ids doesn't exist on this project —
        // show "invite them to Amba" UI.
        return { ok: false, reason: 'recipient_not_on_amba' };
      }
      if (err.code === 'INVALID_PAYLOAD') {
        // participant_ids was empty, malformed, or the type field was bad.
        // err.details.missing lists the missing fields.
        return { ok: false, reason: 'bad_input', details: err.details };
      }
    }
    throw err;
  }
 
  await Amba.messaging.sendMessage(conv.id, { body: firstMessage });
  return { ok: true, conversationId: conv.id };
}

Error codes the messaging surface returns:

CodeWhen
INVALID_JSONRequest body wasn't parseable JSON.
INVALID_PAYLOADRequired field missing or malformed. error.details.missing lists the fields.
USER_NOT_FOUNDOne or more participant_ids don't exist. error.details.missing_user_ids enumerates them.
INVALID_CONVERSATION_IDConversation id isn't a valid UUID.
CONVERSATION_NOT_FOUNDConversation doesn't exist.
NOT_A_PARTICIPANTCaller isn't in the conversation's participant list.

Client API reference

MethodPathDescription
POST/client/messaging/conversationsCreate a conversation
GET/client/messaging/conversationsList user's conversations
POST/client/messaging/conversations/:id/messagesSend a message
GET/client/messaging/conversations/:id/messagesGet messages (paginated)
POST/client/messaging/conversations/:id/readMark conversation as read

Create a conversation

POST /client/messaging/conversations
{
  "participant_ids": ["user_xxx", "user_yyy"],
  "type": "direct"
}

Send a message

POST /client/messaging/conversations/:id/messages
{
  "body": "Hey, want to do a workout challenge together?",
  "metadata": {}
}

MCP tools

ToolDescription
amba_messaging_get_statsGet messaging statistics (total conversations, messages, active count)

On this page