***

title: sendMessage
slug: /reference/typescript/relay/client/send-message
description: Send an outbound SMS or MMS message.
max-toc-depth: 3
---------------------

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

[message]: /docs/server-sdks/reference/typescript/relay/message

Send an outbound SMS or MMS message. Returns a
[`Message`][message] object that tracks delivery
state changes. Use `await message.wait()` to block until the message reaches a
terminal state (delivered, undelivered, or failed).

<Note>
  At least one of `body` or `media` must be provided. Providing both sends an MMS
  with text and attached media.
</Note>

## **Parameters**

<ParamField path="to" type="string" required={true} toc={true}>
  Destination phone number in E.164 format (e.g., `"+15559876543"`).
</ParamField>

<ParamField path="from" type="string" required={true} toc={true}>
  Sender phone number in E.164 format. Must be a number owned by your SignalWire project.
</ParamField>

<ParamField path="context" type="string | undefined" toc={true}>
  Context for receiving state-change events for this message. Defaults to the
  server-assigned relay protocol string, or `"default"` if no protocol has been
  assigned yet.
</ParamField>

<ParamField path="body" type="string | undefined" toc={true}>
  Text body of the message. Required for SMS. Optional for MMS if `media` is provided.
</ParamField>

<ParamField path="media" type="string[] | undefined" toc={true}>
  List of publicly accessible media URLs for MMS attachments (e.g., images, audio files).
</ParamField>

<ParamField path="tags" type="string[] | undefined" toc={true}>
  Optional tags to attach to the message for filtering or tracking.
</ParamField>

<ParamField path="region" type="string | undefined" toc={true}>
  Origination region for the message.
</ParamField>

<ParamField path="onCompleted" type="(event: any) => void | Promise<void>" toc={true}>
  Callback function invoked when the message reaches a terminal state
  (`delivered`, `undelivered`, or `failed`). Receives the terminal
  event as its argument.
</ParamField>

## **Returns**

`Promise<`[`Message`][message]`>` -- A message object in the `"queued"` state. Use `await message.wait()` to block until delivery confirmation.

## **Examples**

### Send SMS

```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: '+15559876543',
  from: '+15551234567',
  body: 'Hello from SignalWire RELAY!',
});
console.log(`Message ID: ${message.messageId}`);

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

await client.disconnect();
```

### Send MMS with media

```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: '+15559876543',
  from: '+15551234567',
  body: 'Check out this image!',
  media: ['https://example.com/photo.jpg'],
});

await client.disconnect();
```

### With completion callback

```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: '+15559876543',
  from: '+15551234567',
  body: 'Important notification',
  onCompleted: (event) => {
    console.log(`Message delivered: ${JSON.stringify(event.params)}`);
  },
});
// No need to await -- callback fires automatically

await client.disconnect();
```