> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # Message > SMS/MMS message tracking and state management. [relayclient-send-message]: /docs/server-sdks/reference/typescript/relay/client/send-message [message-constants]: /docs/server-sdks/reference/typescript/relay/constants [relayevent]: /docs/server-sdks/reference/typescript/relay/events [message-on]: /docs/server-sdks/reference/typescript/relay/message/on [events]: /docs/server-sdks/reference/typescript/relay/events#messaging-events [on]: /docs/server-sdks/reference/typescript/relay/message/on [wait]: /docs/server-sdks/reference/typescript/relay/message/wait The `Message` class represents a single SMS/MMS message in the Relay messaging namespace. It tracks the lifecycle of a sent or received message through state events. Outbound messages progress through `queued`, `initiated`, `sent`, and then reach a terminal state (`delivered`, `undelivered`, or `failed`). Inbound messages arrive fully formed with state `received`. Obtain a `Message` instance from [`RelayClient.sendMessage()`][relayclient-send-message] or from the `client.onMessage()` handler for inbound messages. ```typescript {11} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); await client.connect(); const message = await client.sendMessage({ toNumber: '+15551234567', fromNumber: '+15559876543', body: 'Hello from SignalWire!', }); // Wait for delivery confirmation const result = await message.wait(30); console.log(`Final state: ${message.state}`); await client.disconnect(); ``` ## **Properties** **`messageId`** `string` Unique identifier for this message, assigned by SignalWire. --- **`context`** `string` The messaging context this message belongs to. --- **`direction`** `string` Message direction. Valid values: * `"inbound"` -- incoming message * `"outbound"` -- outgoing message --- **`fromNumber`** `string` Sender phone number in E.164 format. --- **`toNumber`** `string` Recipient phone number in E.164 format. --- **`body`** `string` Text content of the message. --- **`media`** `string[]` List of media URLs for MMS messages. Empty list for SMS-only messages. --- **`segments`** `number` Number of SMS segments required for this message. --- **`state`** `string` Current message state. See [`Message Constants`][message-constants] for valid values. * `"queued"` -- message has been accepted and is waiting to be processed * `"initiated"` -- message processing has started * `"sent"` -- message has been dispatched to the carrier * `"delivered"` -- message was successfully delivered to the recipient * `"undelivered"` -- carrier was unable to deliver the message * `"failed"` -- message could not be sent * `"received"` -- inbound message received from the network --- **`reason`** `string` Failure reason when the message reaches an error state. Empty string if no failure has occurred. --- **`tags`** `string[]` Optional tags associated with this message. --- **`isDone`** `boolean` `true` if the message has reached a terminal state (`delivered`, `undelivered`, or `failed`). Read-only property. --- **`isTerminal`** `boolean` `true` when `state` is `delivered`, `undelivered`, or `failed`. Unlike `isDone`, this tests the state value alone, so it is meaningful on an inbound message before any event has been dispatched. --- **`result`** `RelayEvent | null` The terminal [`RelayEvent`][relayevent] that resolved this message, or `null` if the message has not yet completed. --- ## **Events** Events are emitted during the lifecycle of a message. Register handlers using [`message.on()`][message-on] to react to state changes on outbound messages. See the [Events][events] reference for the full list of messaging events, their parameters, and typed event classes. --- ## **Methods** #### [on](/docs/server-sdks/reference/typescript/relay/message/on) Register an event listener for state changes on this message. #### [wait](/docs/server-sdks/reference/typescript/relay/message/wait) Block until the message reaches a terminal state. ## **Examples** ### Listening for state changes ```typescript {21} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); await client.connect(); const message = await client.sendMessage({ toNumber: '+15551234567', fromNumber: '+15559876543', body: 'Order confirmed', }); const onStateChange = (event) => { console.log(`Message ${message.messageId} -> ${message.state}`); }; message.on(onStateChange); await message.wait(); await client.disconnect(); ``` ### Waiting for delivery with timeout ```typescript {19} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); await client.connect(); const message = await client.sendMessage({ toNumber: '+15551234567', fromNumber: '+15559876543', body: 'Your verification code is 123456', }); try { const event = await message.wait(30); if (message.state === 'delivered') { console.log('Message delivered successfully'); } else { console.log(`Message failed: ${message.reason}`); } } catch (err) { console.log('Timed out waiting for delivery confirmation'); } await client.disconnect(); ``` > SMS/MMS message tracking and state management. ## Docs - [on](https://signalwire.com/docs/server-sdks/reference/typescript/relay/message/on.md): Register an event listener for state changes on this message. - [wait](https://signalwire.com/docs/server-sdks/reference/typescript/relay/message/wait.md): Await until the message reaches a terminal state.