This guide covers the message stream on an active interaction - consuming real-time voice transcriptions, and sending, receiving, and paging through private text messages. Both arrive as typed messages discriminated by their type and subtype.
Personas: Agent - sends and receives private messages and consumes live transcriptions on their own call; Supervisor - reads transcriptions and sends private coaching messages while monitoring an interaction.
Messages are delivered over the InteractionEventType.INTERACTION_MESSAGE_RECEIVED event and discriminated by type and subType:
subType === ChatMessageSubType.TRANSCRIPTION. No additional subscription or API setup is required beyond listening for incoming messages on a voice interaction.INTERACTION_MESSAGE_RECEIVED / INTERACTION_MESSAGE_SENT events.interaction.canSendMessage() and interaction.canGetMessages() to guard at runtime.Filter incoming messages by type then subType. Narrowing to MessageType.CHAT is required before accessing subType, which is only present on ChatMessage:
interaction.subscribe(InteractionEventType.INTERACTION_MESSAGE_RECEIVED, (event) => {
const { message } = event.payload;
if (message.type !== MessageType.CHAT) return;
if (message.subType !== ChatMessageSubType.TRANSCRIPTION) return;
const isCustomer = message.author.type === MessageAuthorType.CUSTOMER;
console.log(isCustomer ? "Customer:" : "Agent:", message.body.text.content, message.createdAt);
});
Each transcription carries an author whose type identifies who spoke:
author.type |
direction |
Who spoke |
|---|---|---|
MessageAuthorType.CUSTOMER |
MessageDirection.IN |
The customer |
MessageAuthorType.AGENT |
MessageDirection.OUT |
The agent or supervisor |
When author.type is MessageAuthorType.CUSTOMER, the author is a CustomerAuthor. Its details property holds a snapshot of Interaction.customer captured at transcription time - prefer author.details over reading interaction.customer directly, since the snapshot is scoped to that specific utterance:
interaction.subscribe(InteractionEventType.INTERACTION_MESSAGE_RECEIVED, (event) => {
const { message } = event.payload;
if (message.type !== MessageType.CHAT) return;
if (message.subType !== ChatMessageSubType.TRANSCRIPTION) return;
if (message.author.type !== MessageAuthorType.CUSTOMER) return;
const { name, phone } = message.author.details;
console.log(`${name} (${phone}): ${message.body.text.content}`);
});
Subscribe to INTERACTION_MESSAGE_RECEIVED on the interaction to handle incoming messages in real time. The handler receives an event object; the message is under event.payload.message. Store the returned handler ID so you can clean up later:
const handlerId = interaction.subscribe(InteractionEventType.INTERACTION_MESSAGE_RECEIVED, (event) => {
const { message } = event.payload;
if (!message.isPrivate) return;
console.log(message.author.type, message.body.text.content, message.createdAt);
});
// unsubscribe when the component unmounts or the interaction completes
interaction.unsubscribe(InteractionEventType.INTERACTION_MESSAGE_RECEIVED, handlerId);
INTERACTION_MESSAGE_SENT fires with the same event shape when the server acknowledges a message you sent.
Guard with canSendMessage() before calling InteractionTrait.sendMessage. Build the request with ChatMessageRequest - messages are always sent with ChatMessageVisibility.PRIVATE visibility (PUBLIC is reserved):
if (interaction.canSendMessage()) {
const request = new ChatMessageRequest().setText("How can I help you today?");
const identifier = await interaction.sendMessage(request);
console.log("sent:", identifier.messageId);
}
InteractionTrait.getMessages returns a MessagesIterator. Call hasNext() before next() and hasPrevious() before previous() - calling either iterator method without checking its guard throws immediately:
if (interaction.canGetMessages()) {
const iter = interaction.getMessages({ order: MessageOrder.DESC, pageSize: 20 });
while (iter.hasPrevious()) {
const page = await iter.previous();
for (const message of page) {
if (message.isPrivate) {
console.log(message.author.type, message.body.text.content, message.createdAt);
}
}
}
}
With MessageOrder.DESC (the default), each page arrives newest-first and previous() pages backward toward older history. next() moves forward toward newer messages from the current position.
Failures surface as typed AvayaInfinityAgentSdkErrors with stable codes from AvayaInfinityAgentSdkErrorCodes. Errors that occur on the messaging path belong to the ASE_4xxx family - match error.code against AvayaInfinityAgentSdkErrorCodes to identify the specific failure. If no specific code applies, the SDK falls back to ASE_4000.
Transcription messages are delivered via events and do not introduce error codes beyond those on the messaging path. There are no Promise-rejection paths specific to transcription.