> ## Documentation Index
> Fetch the complete documentation index at: https://learn.social.plus/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Message

> Send app-defined custom chat message payloads.

Use custom messages when your app needs to send structured data that is not one of the built-in text or media message types. Keep the payload JSON-serializable and version your custom schema in your app code so older clients can render safely.

## Parameters

| Parameter      | Required | Description                                                   |
| -------------- | -------- | ------------------------------------------------------------- |
| `subChannelId` | Yes      | Target subchannel where the custom message will be created.   |
| `data`         | Yes      | JSON-serializable custom payload owned by your app.           |
| `parentId`     | No       | Parent message ID when sending the custom message as a reply. |
| `tags`         | No       | App-defined tags for filtering or grouping custom messages.   |
| `metadata`     | No       | App-defined metadata stored with the message.                 |

## Send A Custom Message

Create a custom message with a JSON-serializable payload that your app knows how to render.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const { data: message } = await MessageRepository.createMessage({
    subChannelId,
    dataType: 'custom',
    data: {
      kind: 'location',
      latitude: 13.7563,
      longitude: 100.5018,
    },
  });

  renderResults(message);
  ```

  ```swift iOS theme={null}
  let options = AmityCustomMessageCreateOptions(
      subChannelId: "sub-channel-id",
      data: [
          "kind": "location",
          "latitude": 13.7563,
          "longitude": 100.5018
      ]
  )

  let message = try await messageRepository.createCustomMessage(options: options)
  showSuccessMessage(message.messageId)
  ```

  ```kotlin Android theme={null}
  val data = JsonObject().apply {
      addProperty("kind", "location")
      addProperty("latitude", 13.7563)
      addProperty("longitude", 100.5018)
  }

  val disposable = AmityChatClient.newMessageRepository()
      .createCustomMessage(
          subChannelId = subChannelId,
          data = data,
      )
      .build()
      .send()
      .subscribe(
          { showSuccessMessage() },
          { error -> handleGeneralError(error) },
      )
  ```

  ```dart Flutter theme={null}
  final message = await AmityChatClient.newMessageRepository()
      .createCustomMessage(subChannelId, {
        'kind': 'location',
        'latitude': 13.7563,
        'longitude': 100.5018,
      })
      .send();

  final messageId = message.messageId;
  ```
</CodeGroup>

## Add Tags, Metadata, Or Reply Context

Attach app-owned tags, metadata, or a `parentId` when the custom message needs filtering, rendering context, or reply threading.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { MessageRepository } from '@amityco/ts-sdk';

  const { data: reply } = await MessageRepository.createMessage({
    subChannelId,
    parentId: messageId,
    dataType: 'custom',
    data: {
      kind: 'system-card',
      title: 'Order received',
    },
    tags: ['system'],
    metadata: {
      source: 'checkout',
    },
  });
  ```

  ```dart Flutter theme={null}
  final reply = await AmityChatClient.newMessageRepository()
      .createCustomMessage(subChannelId, {
        'kind': 'system-card',
        'title': 'Order received',
      })
      .parentId(messageId)
      .tags(['system'])
      .metadata({'source': 'checkout'})
      .send();
  ```
</CodeGroup>

## Rendering Guidance

* Treat `data` as an app-owned contract.
* Include a type or version field such as `kind` so clients can choose the renderer.
* Provide a fallback renderer for unknown custom payloads.
* Keep sensitive data out of custom payloads unless your product explicitly requires it.

## Related Topics

<CardGroup cols={2}>
  <Card title="Text Message" href="./text-message" icon="message-square">
    Send plain chat content.
  </Card>

  <Card title="Reply to a Message" href="./reply-to-a-message" icon="reply">
    Send custom replies with `parentId`.
  </Card>
</CardGroup>
