Operations for managing threads in Plain.
Summary
Functions
Adds labels to a thread.
Assigns a thread to a user or machine user.
Changes a thread's priority.
Creates a new thread.
Creates a note on a thread (internal, not visible to the customer).
Deletes a custom thread field.
Fetches a thread by its external ID. External IDs are unique per customer, so the customer ID is also required.
Fetches a thread by its Plain ID (e.g. "th_01HX...").
Returns {:ok, nil} if not found.
Fetches a thread by its human-readable ref (e.g. "T-1234").
Returns {:ok, nil} if not found.
Returns a paginated list of threads.
Marks a thread as done.
Marks a thread as todo (e.g. unsnoozes it).
Removes labels from a thread.
Replies to a thread via the API channel.
Replies to an email on a thread.
Sends a chat message on a thread (agent → customer).
Sends a chat message as the customer (backfill inbound chat).
Sends a new outbound email on a thread.
Snoozes a thread for a given number of seconds.
Unassigns a thread.
Updates the tenant associated with a thread.
Upserts a custom thread field.
Functions
@spec add_labels(ExPlain.Client.t(), String.t(), [String.t()]) :: {:ok, [ExPlain.Labels.Label.t()]} | {:error, ExPlain.Error.t()}
Adds labels to a thread.
Example
ExPlain.Threads.add_labels(client, "th_01HX...", ["lbt_01HX...", "lbt_02HX..."])
@spec assign(ExPlain.Client.t(), String.t(), keyword()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Assigns a thread to a user or machine user.
Pass either user_id: or machine_user_id: in opts.
Example
ExPlain.Threads.assign(client, "th_01HX...", user_id: "usr_01HX...")
@spec change_priority(ExPlain.Client.t(), String.t(), integer()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Changes a thread's priority.
Valid priorities are 0 (urgent), 1 (high), 2 (normal), 3 (low).
@spec create(ExPlain.Client.t(), map()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Creates a new thread.
The input map must include :customer_identifier with one of:
:customer_id, :customer_external_id, or :email_address.
Optional fields: :title, :description, :priority (0–3), :channel,
:label_type_ids, :tenant_identifier, :external_id.
Example
ExPlain.Threads.create(client, %{
customer_identifier: %{customer_id: "c_01HX..."},
title: "Cannot log in",
priority: 1
})
@spec create_note(ExPlain.Client.t(), map()) :: {:ok, map()} | {:error, ExPlain.Error.t()}
Creates a note on a thread (internal, not visible to the customer).
The input map must include :thread_id and :markdown.
@spec delete_field(ExPlain.Client.t(), String.t()) :: {:ok, :deleted} | {:error, ExPlain.Error.t()}
Deletes a custom thread field.
@spec get_by_external_id(ExPlain.Client.t(), String.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t() | nil} | {:error, ExPlain.Error.t()}
Fetches a thread by its external ID. External IDs are unique per customer, so the customer ID is also required.
Returns {:ok, nil} if not found.
@spec get_by_id(ExPlain.Client.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t() | nil} | {:error, ExPlain.Error.t()}
Fetches a thread by its Plain ID (e.g. "th_01HX...").
Returns {:ok, nil} if not found.
@spec get_by_ref(ExPlain.Client.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t() | nil} | {:error, ExPlain.Error.t()}
Fetches a thread by its human-readable ref (e.g. "T-1234").
Returns {:ok, nil} if not found.
@spec list( ExPlain.Client.t(), keyword() ) :: {:ok, %{nodes: [ExPlain.Threads.Thread.t()], page_info: ExPlain.PageInfo.t()}} | {:error, ExPlain.Error.t()}
Returns a paginated list of threads.
Options
Pagination: first:, after:, last:, before:.
Filtering: filters: (passed as a ThreadsFilter input map).
Sorting: sort_by: (passed as a ThreadsSort input map).
@spec mark_as_done(ExPlain.Client.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Marks a thread as done.
@spec mark_as_todo(ExPlain.Client.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Marks a thread as todo (e.g. unsnoozes it).
@spec remove_labels(ExPlain.Client.t(), [String.t()]) :: {:ok, :removed} | {:error, ExPlain.Error.t()}
Removes labels from a thread.
Example
ExPlain.Threads.remove_labels(client, ["lbl_01HX...", "lbl_02HX..."])
@spec reply(ExPlain.Client.t(), map()) :: {:ok, :sent} | {:error, ExPlain.Error.t()}
Replies to a thread via the API channel.
The input map must include :thread_id and :components.
@spec reply_to_email(ExPlain.Client.t(), map()) :: {:ok, :sent} | {:error, ExPlain.Error.t()}
Replies to an email on a thread.
The input map must include :email_id and :components.
@spec send_chat(ExPlain.Client.t(), map()) :: {:ok, map()} | {:error, ExPlain.Error.t()}
Sends a chat message on a thread (agent → customer).
The input map must include :thread_id and one of :text or :attachment_ids.
@spec send_customer_chat(ExPlain.Client.t(), map()) :: {:ok, map()} | {:error, ExPlain.Error.t()}
Sends a chat message as the customer (backfill inbound chat).
The input map must include :thread_id and one of :text or :attachment_ids.
@spec send_email(ExPlain.Client.t(), map()) :: {:ok, :sent} | {:error, ExPlain.Error.t()}
Sends a new outbound email on a thread.
The input map must include :thread_id and :components.
@spec snooze(ExPlain.Client.t(), String.t(), integer()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Snoozes a thread for a given number of seconds.
@spec unassign(ExPlain.Client.t(), String.t()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Unassigns a thread.
@spec update_tenant(ExPlain.Client.t(), map()) :: {:ok, ExPlain.Threads.Thread.t()} | {:error, ExPlain.Error.t()}
Updates the tenant associated with a thread.
@spec upsert_field(ExPlain.Client.t(), map()) :: {:ok, map()} | {:error, ExPlain.Error.t()}
Upserts a custom thread field.
The input map must include :thread_id, :key, :type, and either
:string_value or :boolean_value.