Replies

Send a response on the channel the event arrived on.

client.on(async (event) => {
  if (event.type === "email.received") {
    await client.reply(event, { text: "Got it. We're on it." });
  }
});

reply() returns a ReplyReceipt:

const receipt = await client.reply(event, { text: "hi" });
receipt.replyId;     // server-side UUID
receipt.acceptedAt;  // Date — server's accept time

Email params

await client.reply(event, {
  text: "Plain-text body (required).",
  html: "<p>Optional rich body.</p>",
  subject: "Optional subject override (defaults to 'Re: <original>').",
  cc: ["ops@acme.com"],
  bcc: ["archive@acme.com"],
});

Slack params

Slack replies only accept text. CC, BCC, subject, and HTML are rejected as invalid for Slack.

await client.reply(event, { text: "👀 on it. will report back." });

The reply is posted back into the channel the event came from, threaded under the originating message.

Per-channel validation

The SDK validates params against the channel type before hitting the network:

// event.type === "webhook.received"
await client.reply(event, { text: "hi" });
// ↑ UnsupportedChannelError: replies are not supported for "webhook" channels yet.

// event.type === "slack.event"
await client.reply(event, { text: "hi", subject: "oops" });
// ↑ RequestError: subject is not supported for slack replies.

Today, email and slack accept replies. webhook and cron do not.

Limits

Email replies are capped to protect customer domain reputation:

FieldLimit
cc + bcc5 addresses combined.
subject512 characters.
text256 KB.

Exceeding any cap returns RequestError with one of: too_many_recipients, subject_too_long, body_too_large.

Threading

Email: no action needed. Nevo stamps In-Reply-To + References and adds a Re: prefix when you don’t override the subject.

Slack: also automatic. Replies to a top-level @mention start a thread under it; replies to threaded messages post into the same thread.

Errors

ExceptionWhenRetry?
UnsupportedChannelErrorChannel doesn’t support replies.No.
RequestErrorClient-side validation or server 4xx.No.
ServerErrorServer 5xx after retries.Yes (later).
NetworkErrorNetwork failure after retries.Yes (later).
AuthErrorToken rejected.No. Fix key.

All inherit from ReplyError. Check .isTransient if you need to gate retry logic:

try {
  await client.reply(event, { text: "hi" });
} catch (err) {
  if (err instanceof ReplyError && err.isTransient) {
    // queue for a retry later
  } else {
    throw err;
  }
}

See Errors for the full hierarchy.