# `Jido.Chat.Adapter`
[🔗](https://github.com/agentjido/jido_chat/blob/v1.0.0/lib/jido/chat/adapter.ex#L1)

Canonical adapter behavior for Chat SDK style integrations.

Thread-aware channel contract for Chat SDK integrations.

# `capability_matrix`

```elixir
@type capability_matrix() :: %{optional(atom()) =&gt; capability_status()}
```

# `capability_status`

```elixir
@type capability_status() :: :native | :fallback | :unsupported
```

# `delete_result`

```elixir
@type delete_result() :: :ok | {:error, term()}
```

# `ephemeral_result`

```elixir
@type ephemeral_result() :: {:ok, Jido.Chat.EphemeralMessage.t()} | {:error, term()}
```

# `external_message_id`

```elixir
@type external_message_id() :: String.t() | integer()
```

# `external_room_id`

```elixir
@type external_room_id() :: String.t() | integer()
```

# `external_user_id`

```elixir
@type external_user_id() :: String.t() | integer()
```

# `file_input`

```elixir
@type file_input() :: Jido.Chat.FileUpload.input()
```

# `incoming_result`

```elixir
@type incoming_result() :: {:ok, Jido.Chat.Incoming.t()} | {:error, term()}
```

# `listener_opts`

```elixir
@type listener_opts() :: keyword()
```

# `message_page_result`

```elixir
@type message_page_result() :: {:ok, Jido.Chat.MessagePage.t()} | {:error, term()}
```

# `message_result`

```elixir
@type message_result() :: {:ok, Jido.Chat.Message.t()} | {:error, term()}
```

# `metadata_result`

```elixir
@type metadata_result() :: {:ok, Jido.Chat.ChannelInfo.t()} | {:error, term()}
```

# `modal_result`

```elixir
@type modal_result() :: {:ok, Jido.Chat.ModalResult.t()} | {:error, term()}
```

# `raw_payload`

```elixir
@type raw_payload() :: map()
```

# `reaction_result`

```elixir
@type reaction_result() :: :ok | {:error, term()}
```

# `send_result`

```elixir
@type send_result() :: {:ok, Jido.Chat.Response.t()} | {:error, term()}
```

# `sink_mfa`

```elixir
@type sink_mfa() :: {module(), atom(), [term()]}
```

# `thread_page_result`

```elixir
@type thread_page_result() :: {:ok, Jido.Chat.ThreadPage.t()} | {:error, term()}
```

# `thread_result`

```elixir
@type thread_result() :: {:ok, Jido.Chat.Thread.t()} | {:error, term()}
```

# `typing_result`

```elixir
@type typing_result() :: :ok | {:error, term()}
```

# `add_reaction`
*optional* 

```elixir
@callback add_reaction(
  external_room_id(),
  external_message_id(),
  emoji :: String.t(),
  opts :: keyword()
) :: :ok | {:ok, term()} | {:error, term()}
```

# `capabilities`
*optional* 

```elixir
@callback capabilities() :: capability_matrix()
```

# `channel_type`

```elixir
@callback channel_type() :: atom()
```

# `delete_message`
*optional* 

```elixir
@callback delete_message(external_room_id(), external_message_id(), opts :: keyword()) ::
  :ok | {:ok, term()} | {:error, term()}
```

# `edit_message`
*optional* 

```elixir
@callback edit_message(
  external_room_id(),
  external_message_id(),
  text :: String.t(),
  opts :: keyword()
) :: send_result() | {:ok, map()} | {:error, term()}
```

# `fetch_channel_messages`
*optional* 

```elixir
@callback fetch_channel_messages(external_room_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.MessagePage.t() | map()} | {:error, term()}
```

# `fetch_message`
*optional* 

```elixir
@callback fetch_message(external_room_id(), external_message_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.Message.t() | Jido.Chat.Incoming.t() | map()}
  | {:error, term()}
```

# `fetch_messages`
*optional* 

```elixir
@callback fetch_messages(external_room_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.MessagePage.t() | map()} | {:error, term()}
```

# `fetch_metadata`
*optional* 

```elixir
@callback fetch_metadata(external_room_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.ChannelInfo.t() | map()} | {:error, term()}
```

# `fetch_thread`
*optional* 

```elixir
@callback fetch_thread(external_room_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.Thread.t() | map()} | {:error, term()}
```

# `format_webhook_response`
*optional* 

```elixir
@callback format_webhook_response(term(), opts :: keyword()) ::
  Jido.Chat.WebhookResponse.t()
  | map()
  | {:ok, Jido.Chat.WebhookResponse.t() | map()}
  | {:error, term()}
```

# `handle_webhook`
*optional* 

```elixir
@callback handle_webhook(chat :: Jido.Chat.t(), raw_payload(), opts :: keyword()) ::
  {:ok, Jido.Chat.t(), Jido.Chat.Incoming.t()} | {:error, term()}
```

# `initialize`
*optional* 

```elixir
@callback initialize(opts :: keyword()) :: :ok | {:ok, term()} | {:error, term()}
```

# `list_threads`
*optional* 

```elixir
@callback list_threads(external_room_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.ThreadPage.t() | map()} | {:error, term()}
```

# `listener_child_specs`
*optional* 

```elixir
@callback listener_child_specs(bridge_id :: String.t(), opts :: listener_opts()) ::
  {:ok, [Supervisor.child_spec()]} | {:error, term()}
```

Optional listener child-spec callback for adapter-owned ingress workers.

Listener workers should emit inbound payloads/events through a sink MFA provided
in `opts` to avoid coupling adapter packages to runtime implementations.

Expected listener opts keys:
  * `:sink_mfa` - sink callback MFA, typically `{Module, :function, [base_args...]}`
  * `:bridge_id` - configured bridge identifier
  * `:bridge_config` - resolved bridge config struct/map
  * `:instance_module` - runtime instance module (opaque to adapters)
  * `:settings` - adapter-specific ingress settings map
  * `:ingress` - normalized ingress mode/settings map

# `open_dm`
*optional* 

```elixir
@callback open_dm(external_user_id(), opts :: keyword()) ::
  {:ok, external_room_id()} | {:error, term()}
```

# `open_modal`
*optional* 

```elixir
@callback open_modal(external_room_id(), payload :: map(), opts :: keyword()) ::
  {:ok, Jido.Chat.ModalResult.t() | map()} | {:error, term()}
```

# `open_thread`
*optional* 

```elixir
@callback open_thread(external_room_id(), external_message_id(), opts :: keyword()) ::
  {:ok, Jido.Chat.Thread.t() | map()} | {:error, term()}
```

# `parse_event`
*optional* 

```elixir
@callback parse_event(Jido.Chat.WebhookRequest.t() | map(), opts :: keyword()) ::
  {:ok, Jido.Chat.EventEnvelope.t() | map() | :noop | nil} | {:error, term()}
```

# `post_channel_message`
*optional* 

```elixir
@callback post_channel_message(external_room_id(), text :: String.t(), opts :: keyword()) ::
  send_result() | {:ok, map()} | {:error, term()}
```

# `post_ephemeral`
*optional* 

```elixir
@callback post_ephemeral(
  external_room_id(),
  external_user_id(),
  text :: String.t(),
  opts :: keyword()
) :: {:ok, Jido.Chat.EphemeralMessage.t() | map()} | {:error, term()}
```

# `post_message`
*optional* 

```elixir
@callback post_message(
  external_room_id(),
  payload :: Jido.Chat.PostPayload.t(),
  opts :: keyword()
) ::
  send_result() | {:ok, map()} | {:error, term()}
```

# `remove_reaction`
*optional* 

```elixir
@callback remove_reaction(
  external_room_id(),
  external_message_id(),
  emoji :: String.t(),
  opts :: keyword()
) :: :ok | {:ok, term()} | {:error, term()}
```

# `send_file`
*optional* 

```elixir
@callback send_file(external_room_id(), file :: file_input(), opts :: keyword()) ::
  send_result() | {:ok, map()} | {:error, term()}
```

# `send_message`

```elixir
@callback send_message(external_room_id(), text :: String.t(), opts :: keyword()) ::
  send_result() | {:ok, map()} | {:error, term()}
```

# `shutdown`
*optional* 

```elixir
@callback shutdown(opts :: keyword()) :: :ok | {:ok, term()} | {:error, term()}
```

# `start_typing`
*optional* 

```elixir
@callback start_typing(external_room_id(), opts :: keyword()) ::
  :ok | {:ok, term()} | {:error, term()}
```

# `stream`
*optional* 

```elixir
@callback stream(external_room_id(), stream :: Enumerable.t(), opts :: keyword()) ::
  send_result() | {:ok, map()} | {:error, term()}
```

# `transform_incoming`

```elixir
@callback transform_incoming(raw_payload()) :: incoming_result() | {:ok, map()}
```

# `verify_webhook`
*optional* 

```elixir
@callback verify_webhook(Jido.Chat.WebhookRequest.t() | map(), opts :: keyword()) ::
  :ok | {:error, term()}
```

# `adapter_type`

```elixir
@spec adapter_type(module()) :: atom()
```

Returns adapter channel type with fallback to module name.

# `add_reaction`

```elixir
@spec add_reaction(
  module(),
  external_room_id(),
  external_message_id(),
  String.t(),
  keyword()
) ::
  reaction_result()
```

Adds a reaction when supported by adapter.

# `capabilities`

```elixir
@spec capabilities(module()) :: capability_matrix()
```

Returns capability matrix for adapter-native vs fallback support.

# `capability_matrix`

```elixir
@spec capability_matrix(module()) :: Jido.Chat.CapabilityMatrix.t()
```

Returns a normalized typed capability matrix.

# `delete_message`

```elixir
@spec delete_message(module(), external_room_id(), external_message_id(), keyword()) ::
  delete_result()
```

Deletes a previously-sent message when supported by adapter.

# `edit_message`

```elixir
@spec edit_message(
  module(),
  external_room_id(),
  external_message_id(),
  String.t(),
  keyword()
) ::
  send_result()
```

Normalizes adapter edit results to `Jido.Chat.Response`.

# `fetch_channel_messages`

```elixir
@spec fetch_channel_messages(module(), external_room_id(), keyword()) ::
  message_page_result()
```

Fetches channel-level history when supported by adapter.

# `fetch_message`

```elixir
@spec fetch_message(module(), external_room_id(), external_message_id(), keyword()) ::
  message_result()
```

Fetches a normalized message by id when supported.

# `fetch_messages`

```elixir
@spec fetch_messages(module(), external_room_id(), keyword()) :: message_page_result()
```

Fetches thread-level history when supported by adapter.

# `fetch_metadata`

```elixir
@spec fetch_metadata(module(), external_room_id(), keyword()) :: metadata_result()
```

Fetches channel metadata as `Jido.Chat.ChannelInfo`.

# `fetch_thread`

```elixir
@spec fetch_thread(module(), external_room_id(), keyword()) :: thread_result()
```

Fetches thread metadata as a normalized `Jido.Chat.Thread`.

# `format_webhook_response`

```elixir
@spec format_webhook_response(module(), term(), keyword()) ::
  {:ok, Jido.Chat.WebhookResponse.t()} | {:error, term()}
```

Formats a typed webhook response using adapter callback when available.

# `handle_webhook`

```elixir
@spec handle_webhook(module(), Jido.Chat.t(), raw_payload(), keyword()) ::
  {:ok, Jido.Chat.t(), Jido.Chat.Incoming.t()} | {:error, term()}
```

Default helper to normalize webhook payload through `transform_incoming/1`.

# `initialize`

```elixir
@spec initialize(
  module(),
  keyword()
) :: :ok | {:error, term()}
```

Initializes adapter resources when supported.

# `list_threads`

```elixir
@spec list_threads(module(), external_room_id(), keyword()) :: thread_page_result()
```

Lists channel thread summaries when supported by adapter.

# `open_modal`

```elixir
@spec open_modal(module(), external_room_id(), Jido.Chat.Modal.t() | map(), keyword()) ::
  modal_result()
```

Opens adapter-native modal when supported.

# `open_thread`

```elixir
@spec open_thread(module(), external_room_id(), external_message_id(), keyword()) ::
  thread_result()
```

Opens a native platform thread from an existing room message when supported.

# `parse_event`

```elixir
@spec parse_event(module(), Jido.Chat.WebhookRequest.t() | map(), keyword()) ::
  {:ok, Jido.Chat.EventEnvelope.t() | :noop} | {:error, term()}
```

Parses request into a normalized event envelope.

# `post_channel_message`

```elixir
@spec post_channel_message(module(), external_room_id(), String.t(), keyword()) ::
  send_result()
```

Posts a channel-level message using adapter callback or send fallback.

# `post_ephemeral`

```elixir
@spec post_ephemeral(
  module(),
  external_room_id(),
  external_user_id(),
  String.t(),
  keyword()
) ::
  ephemeral_result()
```

Posts an ephemeral message when supported, with optional DM fallback.

# `post_ephemeral_message`

```elixir
@spec post_ephemeral_message(
  module(),
  external_room_id(),
  external_user_id(),
  String.t() | Jido.Chat.Postable.t() | Jido.Chat.PostPayload.t() | map(),
  keyword()
) :: ephemeral_result()
```

Posts an ephemeral payload using the canonical outbound payload contract.

# `post_message`

```elixir
@spec post_message(
  module(),
  external_room_id(),
  Jido.Chat.PostPayload.t() | map(),
  keyword()
) ::
  send_result()
```

Posts a normalized outbound payload using adapter-native or core fallback behavior.

# `remove_reaction`

```elixir
@spec remove_reaction(
  module(),
  external_room_id(),
  external_message_id(),
  String.t(),
  keyword()
) :: reaction_result()
```

Removes a reaction when supported by adapter.

# `render_card`

```elixir
@spec render_card(
  Jido.Chat.Card.t() | map(),
  keyword()
) :: map()
```

Returns a stable adapter-facing card payload.

# `render_markdown`

```elixir
@spec render_markdown(
  Jido.Chat.Markdown.t() | map() | String.t(),
  keyword()
) :: String.t()
```

Returns a stable adapter-facing Markdown representation.

# `render_modal`

```elixir
@spec render_modal(
  Jido.Chat.Modal.t() | map(),
  keyword()
) :: map()
```

Returns a stable adapter-facing modal payload.

# `send_file`

```elixir
@spec send_file(module(), external_room_id(), file_input(), keyword()) ::
  send_result()
```

Uploads and sends a file when supported by the adapter.

# `send_message`

```elixir
@spec send_message(module(), external_room_id(), String.t(), keyword()) ::
  send_result()
```

Normalizes adapter send results to `Jido.Chat.Response`.

# `shutdown`

```elixir
@spec shutdown(
  module(),
  keyword()
) :: :ok | {:error, term()}
```

Shuts down adapter resources when supported.

# `start_typing`

```elixir
@spec start_typing(module(), external_room_id(), keyword()) :: typing_result()
```

Starts typing indicator when supported by adapter.

# `stream`

```elixir
@spec stream(module(), external_room_id(), Enumerable.t(), keyword()) :: send_result()
```

Streams chunked text using adapter stream callback or send fallback.

# `transform_incoming`

```elixir
@spec transform_incoming(module(), raw_payload()) :: incoming_result()
```

Normalizes adapter inbound transformation to `Jido.Chat.Incoming`.

# `validate_capabilities`

```elixir
@spec validate_capabilities(module()) :: :ok | {:error, term()}
```

Validates capability declaration coherence with implemented callbacks.

# `verify_webhook`

```elixir
@spec verify_webhook(module(), Jido.Chat.WebhookRequest.t() | map(), keyword()) ::
  :ok | {:error, term()}
```

Verifies webhook request integrity when adapter exposes validation callback.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
