***

title: Message
slug: /reference/typescript/relay/message
description: SMS/MMS message tracking and state management.
max-toc-depth: 3
---------------------

For a complete index of all SignalWire documentation pages, fetch https://signalwire.com/docs/llms.txt

[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_TOKEN!,
  contexts: ['default']
});

await client.connect();

const message = await client.sendMessage({
  to: '+15551234567',
  from: '+15559876543',
  body: 'Hello from SignalWire!',
});

// Wait for delivery confirmation
const result = await message.wait(30_000);
console.log(`Final state: ${message.state}`);

await client.disconnect();
```

## **Properties**

<ParamField path="messageId" type="string" toc={true}>
  Unique identifier for this message, assigned by SignalWire.
</ParamField>

<ParamField path="context" type="string" toc={true}>
  The messaging context this message belongs to.
</ParamField>

<ParamField path="direction" type="string" toc={true}>
  Message direction. Valid values:

  * `"inbound"` -- incoming message
  * `"outbound"` -- outgoing message
</ParamField>

<ParamField path="fromNumber" type="string" toc={true}>
  Sender phone number in E.164 format.
</ParamField>

<ParamField path="toNumber" type="string" toc={true}>
  Recipient phone number in E.164 format.
</ParamField>

<ParamField path="body" type="string" toc={true}>
  Text content of the message.
</ParamField>

<ParamField path="media" type="string[]" toc={true}>
  List of media URLs for MMS messages. Empty list for SMS-only messages.
</ParamField>

<ParamField path="segments" type="number" toc={true}>
  Number of SMS segments required for this message.
</ParamField>

<ParamField path="state" type="string" toc={true}>
  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
</ParamField>

<ParamField path="reason" type="string" toc={true}>
  Failure reason when the message reaches an error state. Empty string if no failure has occurred.
</ParamField>

<ParamField path="tags" type="string[]" toc={true}>
  Optional tags associated with this message.
</ParamField>

<ParamField path="isDone" type="boolean" toc={true}>
  `true` if the message has reached a terminal state (`delivered`, `undelivered`, or `failed`).
  Read-only property.
</ParamField>

<ParamField path="result" type="RelayEvent | null" toc={true}>
  The terminal [`RelayEvent`][relayevent] that resolved this message,
  or `null` if the message has not yet completed.
</ParamField>

## **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**

<CardGroup cols={2}>
  <Card title="on" href="/docs/server-sdks/reference/typescript/relay/message/on">
    Register an event listener for state changes on this message.
  </Card>

  <Card title="wait" href="/docs/server-sdks/reference/typescript/relay/message/wait">
    Block until the message reaches a terminal state.
  </Card>
</CardGroup>

## **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_TOKEN!,
  contexts: ['default']
});

await client.connect();

const message = await client.sendMessage({
  to: '+15551234567',
  from: '+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_TOKEN!,
  contexts: ['default']
});

await client.connect();

const message = await client.sendMessage({
  to: '+15551234567',
  from: '+15559876543',
  body: 'Your verification code is 123456',
});

try {
  const event = await message.wait(30_000);
  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();
```