# Messages Overview

Let's dive right into it, the example below shows how to send a simple message using Stream:

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val channelClient = client.channel("messaging", "general")
val message = Message(
  text = "Josh, I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish."
)

channelClient.sendMessage(message).enqueue { result ->
  if (result is Result.Success) {
    val sentMessage: Message = result.value
  } else {
    // Handle Result.Failure
  }
}
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
const message = await channel.sendMessage({
  text: "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
});
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
import StreamChat

/// 1: Create a `ChannelId` that represents the channel you want to send a message to.
let channelId = ChannelId(type: .messaging, id: "general")

/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let channelController = chatClient.channelController(for: channelId)

/// 3: Call `ChatChannelController.createNewMessage` to create the message.
channelController.createNewMessage(text: "Hello") { result in
  switch result {
  case .success(let messageId):
    print(messageId)
  case .failure(let error):
    print(error)
  }
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final message = Message(
 text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.'
);

await channel.sendMessage(message);
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Sending a message from jenny mentioning bob-1

$message = $channel->sendMessage([
	'text' => '@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.',
	],
	'jenny');
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
message = {
  "text": "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
}

channel.send_message(message, user_id)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
message := &stream_chat.Message{
	Text: "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
}

filledMessage, err := channel.SendMessage(message, userID)
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
const FMessage Message{TEXT("@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")};
Channel->SendMessage(Message);
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await messageClient.SendMessageAsync(channel.Type, channel.Id, "jenny", "@Bob I told them I was pesca-pescatarian.");
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# require 'stream-chat'

message = {
  "text" => "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
}

channel.send_message(message, user_id)
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
var message = await channel.SendNewMessageAsync("Hello world!");
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Android SDK
ChannelClient channelClient = client.channel("messaging", "general");
Message message = new Message();
message.setText("Josh, I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.");

channelClient.sendMessage(message).enqueue(result -> {
  if (result.isSuccess()) {
    Message sentMessage = result.data();
  } else {
    // Handle result.error()
  }
});

// Backend SDK
Message.send(type, id)
  .message(
    MessageRequestObject.builder()
      .text(
        "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")
      .userId(userId)
      .build())
  .request();
```

</codetabs-item>

</codetabs>

Note how server side SDKs require that you specify user_id to indicate who is sending the message. You can add custom fields to both the message and the attachments. There's a 5KB limit for the custom fields. File uploads are uploaded to the CDN so don't count towards this 5KB limit.

| name                  | type   | description                                                                                                                                      | default | optional |
| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -------- |
| text                  | string | The text of the chat message (Stream chat supports markdown and automatically enriches URLs).                                                    |         | ✓        |
| attachments           | array  | A list of attachments (audio, videos, images, and text). Max is 30 attachments per message. The total combined attachment size can't exceed 5KB. |         |          |
| user_id               | object | This value is automatically set in client-side mode. You only need to send this value when using the server-side APIs.                           |         | ✓        |
| mentioned_users       | array  | A list of users mentioned in the message. You send this as a list of user IDs and receive back the full user data.                               |         |          |
| message custom data   | object | Extra data for the message. Must not exceed 5KB in size.                                                                                         |         |          |
| skip_push             | bool   | Do not send a push notification.                                                                                                                 | false   | ✓        |
| restricted_visibility | bool   | Send the message only to particular channel members, represented with their user ids.                                                            |         | ✓        |

## Complex Example

A more complex example for creating a message is shown below:

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Create an image attachment
val attachment = Attachment(
  type = "image",
  imageUrl = "https://bit.ly/2K74TaG",
  thumbUrl = "https://bit.ly/2Uumxti",
  extraData = mutableMapOf("myCustomField" to 123),
)

// Create a message with the attachment and a user mention
val message = Message(
  text = "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
  attachments = mutableListOf(attachment),
  mentionedUsersIds = mutableListOf("josh-id"),
  extraData = mutableMapOf("anotherCustomField" to 234),
)

// Send the message to the channel
channelClient.sendMessage(message).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
const message = await channel.sendMessage(
  {
    text: "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
    attachments: [
      {
        type: "image",
        asset_url: "https://bit.ly/2K74TaG",
        thumb_url: "https://bit.ly/2Uumxti",
        myCustomField: 123,
      },
    ],
    mentioned_users: [josh.id],
    anotherCustomField: 234,
  },
  { skip_push: true },
);
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// 1: Create a `ChannelId` that represents the channel you want to send a message to.
let channelId = ChannelId(type: .messaging, id: "general")

// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let channelController = chatClient.channelController(for: channelId)

// 3: Call `ChatChannelController.createNewMessage`
let fileURL = URL(filePath: "<file url>")
let attachment = try AnyAttachmentPayload(
  localFileURL: fileURL,
  attachmentType: .file
)
channelController.createNewMessage(
  text: "Hello",
  pinning: .noExpiration,
  isSilent: false,
  attachments: [attachment],
  mentionedUserIds: [],
  quotedMessageId: "quotedid",
  skipPush: false,
  skipEnrichUrl: false,
  restrictedVisibility: [],
  extraData: ["priority": .bool(true)]) { result in
    // …
  }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final message = Message(
 text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.',
 attachments: [
  Attachment(
   type: "image",
   assetUrl: "https://bit.ly/2K74TaG",
   thumbUrl: "https://bit.ly/2Uumxti",
   extraData: {
    "myCustomField": 123,
   }
  ),
 ],
 mentionedUsers: [
  User(id: "josh")
 ],
 extraData: {
  "anotherCustomField": 234,
 },
);

await channel.sendMessage(message);
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Sending a message from jenny mentioning bob-1

$message = $channel->sendMessage([
	'text' => '@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.',
	'attachments' =>
		[
			[
				'type' => 'image',
				'asset_url' => 'https://bit.ly/2K74TaG',
				'thumb_url' => 'https://bit.ly/2Uumxti',
				'myCustomField' => 123
			]

		],
	'mentioned_users' => ['bob-1'],
	'anotherCustomField' => 456
	],
	'jenny');
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
message = {
  "text": "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
  "attachments": [
    {
      "type": "image",
      "asset_url": "https://bit.ly/2K74TaG",
      "thumb_url": "https://bit.ly/2Uumxti",
      "myCustomField": 123,
    }
  ],
  "mentioned_users": ["bob-1"],
  "anotherCustomField": 456,
}

channel.send_message(message, user_id)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
message := &stream_chat.Message{
	Text: "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
	Attachments: []*stream_chat.Attachment{
		&stream_chat.Attachment{
			Type:   "image",
			ThumbURL: "https://bit.ly/2K74TaG",
			AssetURL: "https://bit.ly/2Uumxti",
			ExtraData: map[string]interface{}{
				"myCustomField": 123,
			},
		},
	},

	ExtraData: map[string]interface{}{
		"anotherCustomField": 456,
	},

	MentionedUsers: []*stream_chat.User{
		&stream_chat.User{Name: "bob-1"},
	},
}

filledMessage, err := channel.SendMessage(message, userID, MessageSkipPush) // You can provide multiple SendMessageOption options. In this case MessageSkipPush, will prevent sending a push notification
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
FMessage Message{TEXT("@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")};
Message.ExtraData.SetNumber(TEXT("anotherCustomField"), 234);
Channel->SendMessage(Message);
// NOTE: the Unreal SDK does not currently support attachments or mentioned users
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
message = {
  "text" => "@Bob I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.",
  "attachments" => [
    {
      "type" => "image",
      "asset_url" => "https://bit.ly/2K74TaG",
      "thumb_url" => "https://bit.ly/2Uumxti",
      "myCustomField" => 123,
    }
  ],
  "mentioned_users" => ["bob-1"],
  "anotherCustomField" => 456,
}

channel.send_message(message, user_id)
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await messageClient.SendMessageAsync(_channel.Type, _channel.Id, new MessageRequest
{
  Text = "@Bob I told them I was pesca-pescatarian.",
  Attachments = new[]
  {
    new Attachment
    {
      Type = "image",
      AssetURL = "https://bit.ly/2K74TaG",
      ThumbURL = "https://bit.ly/2Uumxti",
    },
  },
  MentionedUsers = new[] { "bob-1" },
}, userId);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Android SDK
// Create an image attachment
Attachment attachment = new Attachment();
attachment.setType("image");
attachment.setImageUrl("https://bit.ly/2K74TaG");
attachment.setThumbUrl("https://bit.ly/2Uumxti");
attachment.getExtraData().put("myCustomField", 123);

// Create a message with the attachment and a user mention
Message message = new Message();
message.setText("@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.");
message.getAttachments().add(attachment);
message.setMentionedUsersIds(Arrays.asList("josh-id"));
message.getExtraData().put("anotherCustomField", 234);

// Send the message to the channel
channelClient.sendMessage(message).enqueue(result -> { /* ... */ });

// Backend SDK
Message.send(type, id)
  .message(
    MessageRequestObject.builder()
      .text(
        "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")
      .attachment(
        AttachmentRequestObject.builder()
          .type("image")
          .assetURL("https://bit.ly/2K74TaG")
          .thumbURL("https://bit.ly/2Uumxti")
          .additionalField("myCustomField", 123)
          .build())
      .mentionedUsers(Arrays.asList(josh.getId()))
      .additionalField("anotherCustomField", 234)
      .userId(userId)
      .build())
  .skipPush(true)
  .request();
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, "my-channel-id");

IStreamUser someUser = null;

// Send simple message with text only
var message3 = await channel.SendNewMessageAsync("Hello");

// Send simple message with text only
var message2 = await channel.SendNewMessageAsync("Let's start a thread!");

var message = await channel.SendNewMessageAsync(new StreamSendMessageRequest
{
  MentionedUsers = new List<IStreamUser> { someUser }, // Mention a user
  ParentId = message2.Id, // Write in thread
  PinExpires = new DateTimeOffset(DateTime.Now).AddDays(7), // Pin for 7 days
  Pinned = true,
  QuotedMessage = message3,
  ShowInChannel = true,
  Text = "Hello",
  CustomData = new StreamCustomDataRequest
  {
    { "my_lucky_numbers", new List<int> { 7, 13, 81 } }
  }
});
```

</codetabs-item>

</codetabs>

<admonition type="warning">

mentioned_users field must contain a maximum of 25 items.

</admonition>

By default Stream’s UI components support the following attachment types:

- Audio
- Video
- Image
- Text

You can specify different types as long as you implement the frontend rendering logic to handle them. Common use cases include:

- Embedding products (photos, descriptions, outbound links, etc.)
- Sharing of a users location

The [React tutorial](https://getstream.io/chat/react-chat/tutorial/) for Stream Chat explains how to customize the `Attachment` component.

## Get a Message

You can get a single message by its ID using the `getMessage` call:

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
channelClient.getMessage("message-id").enqueue { result ->
  if (result is Result.Success) {
    val message: Message = result.value
  } else {
    // Handle Result.Failure
  }
}
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.getMessage(messageID);

//if a message was soft-deleted it returns the original message
await serverClient.getMessage(messageID, { show_deleted_message: true });
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
import StreamChat

/// 1: Create a `ChannelId` that represents the channel you want to get a message from.
let channelId = ChannelId(type: .messaging, id: "general")

/// 1: Create a `MessageId` that represents the message you want to get.
let messageId = "message-id"

/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`.
let messageController = chatClient.messageController(cid: channelId, messageId: messageId)

/// 3: Call `ChatChannelController.createNewMessage` to create the message.
messageController.synchronize { error in
  // handle possible errors / access message
  print(error ?? messageController.message!)
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final message = await client.getMessage("message-id");
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$message = $client->getMessage('message-id');
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
response = client.get_message(msg_id)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
msg, err := client.GetMessage(msgID)
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Channel->GetMessage(TEXT("message-id"));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
response = client.get_message(msg_id)
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await messageClient.GetMessageAsync(message.Id);
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Android SDK
channelClient.getMessage("message-id").enqueue(result -> {
  if (result.isSuccess()) {
    Message message = result.data();
  } else {
    // Handle result.error()
  }
});

// Backend SDK
Message.get(messageId).request();
```

</codetabs-item>

</codetabs>

## Get a Message Options

| name                 | type    | description                           | default | optional |
| -------------------- | ------- | ------------------------------------- | ------- | -------- |
| show_deleted_message | boolean | if true, returns the original message | false   | ✓        |

<admonition type="info">

**show_deleted_message** is exposed for server-side calls only.

</admonition>

## Update a Message

You can edit a message by calling  `updateMessage` and including a message with an ID – the ID field is _required_ when editing a message:

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Update some field of the message
val message = messageToUpdate.copy(text = "my updated text")

// Send the message to the channel
channelClient.updateMessage(message).enqueue { result ->
  if (result is Result.Success) {
    val updatedMessage: Message = result.value
  } else {
    // Handle Result.Failure
  }
}
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
const message = { id: 123, text: "the edited version of my text" };
const update = await client.updateMessage(message);
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
messageController.editMessage(text: "Hello!!!") { error in
  // handle possible errors / access message
  print(error ?? messageController.message!)
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
await client.updateMessage(Message(id: "123", text: "the edited version of my text"));
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$message = [
	'user_id' => 'jenny',
	'id' => 'message-id',
	'text' => 'the edited version of my text'
];

$update = $client->updateMessage($message);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.update_message(
  {
    "id": msg_id,
    "text": "the edited version of my text",
    "user_id": user_id,
  }
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
updatedMessage := &stream_chat.Message{
	ID:  msgID,
	Text: "the edited version of my text",
	User: &stream_chat.User{ID: userID},
}

filledMessage, err := client.UpdateMessage(updatedMessage, msgID)
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Update some field of the message
Message.Text = TEXT("my updated text");

// Send the message to the channel
Channel->UpdateMessage(Message);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.update_message(
  {
    "id" => msg_id,
    "text" => "the edited version of my text",
    "user_id" => user_id,
  }
)
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var updated = await messageClient.UpdateMessageAsync(new MessageRequest
{
  Id = message.Id,
  Text = "the edited version of my text",
  UserId = user.Id,
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, channelId: "my-channel-id");
var message = await channel.SendNewMessageAsync("Hello world!");

// Edit message text and some custom data
await message.UpdateAsync(new StreamUpdateMessageRequest
{
  Text = "Hi everyone!",
  CustomData = new StreamCustomDataRequest
  {
    {"tags", new [] {"Funny", "Unique"}}
  }
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Android SDK

// Update some field of the message
message.setText("my updated text");

// Send the message to the channel
channelClient.updateMessage(message).enqueue(result -> {
  if (result.isSuccess()) {
    Message updatedMessage = result.data();
  } else {
    // Handle result.error()
  }
});

// Backend SDK
Message message = Message.get("123").request().getMessage();
MessageRequestObject messageRequestObject = MessageRequestObject.buildFrom(message);
messageRequestObject.setText("the edited version of my text");
Message.update(message.getId()).message(messageRequestObject).request();
```

</codetabs-item>

</codetabs>

### Partial Update

A partial update can be used to set and unset specific fields when it is necessary to retain additional data fields on the object. AKA a patch style update.

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val originalMessage = channelClient.sendMessage(
    message = Message(
        text = "this message is about to be partially updated",
        extraData = mapOf(
            "color" to "red",
            "details" to mapOf("status" to "pending")
        )
    )
).await().getOrThrow() // get the message object to obtain the auto-generated ID

// partial update message text
val text = "the text was partial updated"
client.partialUpdateMessage(
    messageId = originalMessage.id,
    set = mapOf("text" to text),
).enqueue { /* ... */ }

// unset color property
client.partialUpdateMessage(
    messageId = originalMessage.id,
    unset = listOf("color"),
).enqueue { /* ... */ }

// set nested property
client.partialUpdateMessage(
    messageId = originalMessage.id,
    set = mapOf("details.status" to "complete"),
).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
let originalMessage = (
  await channel.sendMessage({
    text: "this message is about to be partially updated",
    color: "red",
    details: {
      status: "pending",
    },
  })
).message;

// partial update message text
const text = "the text was partial updated";
const updated = await client.partialUpdateMessage(originalMessage.id, {
  set: {
    text,
  },
});

// unset color property
const updated = await client.partialUpdateMessage(originalMessage.id, {
  unset: ["color"],
});

// set nested property
const updated = await client.partialUpdateMessage(originalMessage.id, {
  set: {
    "details.status": "complete",
  },
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Message.partialUpdate(message.getId())
  .setValue("text", "this message just got partially updated")
  .setValue("color", "red")
  .setValue("details.status", "pending") // nested object
  .user(userRequestObject)
  .request();

Message.partialUpdate(message.getId())
  .unsetValue("color")
  .user(testUserRequestObject)
  .request();
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->partialUpdateMessage($messageId, [
 "set" => [
  "text" => "this message just got partially updated",
  "color" => "red",
  "details.status" => "pending" // nested object
 ],
]);

$client->partialUpdateMessage($messageId, [
 "unset" => ["details.status"], // remove nested object
]);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.update_message_partial(
  msg_id,
  {
   "set": {
    "text": "this message just got partially updated",
    "color": "red",
    "details.status": "pending", # nested object
   }
  },
  user["id"],
)

client.update_message_partial(
  msg_id,
  {
   "unset": ["details.status"], # remove nested object
  },
  user["id"],
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
client.PartialUpdateMessage(ctx, msgId, &MessagePartialUpdateRequest{
	PartialUpdate: PartialUpdate{
		Set: map[string]interface{}{
			"text":      "this message just got partially updated",
			"color":     "red",
			"details.status": "pending", // nested object
		},
	},
})

client.PartialUpdateMessage(ctx, msgId, &MessagePartialUpdateRequest{
	PartialUpdate: PartialUpdate{
		Unset: []string{"details.status"}, // remove nested object
	},
})
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.update_message_partial(
  msg_id,
  {
   "set" => {
    "text => "this message just got partially updated",
    "color" => "red",
    "details.status" => "pending", # nested object
   }
  },
  user["id"],
)

client.update_message_partial(
  msg_id,
  {
   "unset" => ["details.status"], # remove nested object
  },
  user["id"],
)
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
await messageClient.UpdateMessagePartialAsync(message.Id, new MessagePartialUpdateRequest
{
  UserId = user.Id,
  Set = new Dictionary<string, object>
  {
    { "text", "this message just got partially updated" },
    { "color", "red" },
    { "details.status", "pending" }, // nested object
  },
});

await messageClient.UpdateMessagePartialAsync(message.Id, new MessagePartialUpdateRequest
{
  UserId = user.Id,
  Unset = new[] { "details.status" }, // remove nested object
});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/
```

</codetabs-item>

</codetabs>

### Delete A Message

You can delete a message by calling  `deleteMessage`   and including a message with an ID. Messages can be soft deleted or hard deleted. Unless specified via the `hard` parameter, messages are soft deleted. Be aware that deleting a message doesn't delete its attachments. See the docs for more information on [deleting attachments](/chat/docs/<framework>/file_uploads/#deleting-files-and-images/).

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
channelClient.deleteMessage("message-id").enqueue { result ->
  if (result is Result.Success) {
    val deletedMessage: Message = result.value
  } else {
    // Handle Result.Error
  }
}
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.deleteMessage(messageID);

// hard delete the message
await client.deleteMessage(messageID, true);
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
messageController.deleteMessage { error in
  // handle possible errors
  print(error ?? "success")
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
await client.deleteMessage("123");
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// soft delete the message
$client->deleteMessage('message-id');

// hard delete the message
$client->deleteMessage('message-id', ['hard' => true]);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# soft delete a message
client.delete_message(msg_id)

# hard delete a message
client.delete_message(msg_id, hard=True)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Soft Delete
err := client.DeleteMessage(msgID)
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Channel->DeleteMessage(Message);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# soft delete a message
client.delete_message(msg_id)

# hard delete a message
client.delete_message(msg_id, hard: True)
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// soft delete a message
await messageClient.DeleteMessageAsync(message.Id);

// hard delete a message
await messageClient.DeleteMessageAsync(message.Id, hardDelete: true);
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Soft delete
await message.SoftDeleteAsync();

// Hard delete
await message.HardDeleteAsync();
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Android SDK
channelClient.deleteMessage("message-id", false).enqueue(result -> {
  if (result.isSuccess()) {
    Message deletedMessage = result.data();
  } else {
    // Handle result.error()
  }
});

// Backend SDK
Message.delete(messageId)
  .hard(true) // Optionally do a hard-delete
  .request();
```

</codetabs-item>

</codetabs>

![](https://user-images.githubusercontent.com/88735/75777352-2060b200-5d56-11ea-91c6-3fcdc13c117f.png)

#### Soft delete

1. Can be done client-side by users

2. Message is still returned in the message list and all its data is kept as it is

3. Message type is set to "deleted"

4. Reactions and replies are kept in place

5. Can be undeleted

#### Hard delete

1. Can be done client-side by users but be cautious this action is not recoverable

2. The message is removed from the channel and its data is wiped

3. All reactions are deleted

4. All replies and their reactions are deleted

By default messages are soft deleted, this is a great way to keep the channel history consistent.

### Undelete a message

A message that was soft-deleted can be undeleted. This is only allowed for server-side clients. The `userID` specifies the user that undeleted the message, which can be used for auditing purposes.

Messages can be undeleted if:

- The message was soft-deleted

- The channel has not been deleted

- It is not a reply to a deleted message. If it is, the parent must be undeleted first

- The user that undeletes the message is valid

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.undeleteMessage(messageID, userID);
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->undeleteMessage('message-id', 'user-id');
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.undelete_message(msg_id, user_id)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.undelete_message(msg_id, user_id)
```

</codetabs-item>

</codetabs>

---

This page was last updated at 2025-08-15T14:15:20.081Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/ruby/send_message/](https://getstream.io/chat/docs/ruby/send_message/).