Email and the messages API

Understand why Samva exposes both an email send facade and a messages API, and how each fits your integration.

Use email.send() for TypeScript email integrations. It sends through the same endpoint as messages.send(), which mirrors the channel-aware body of POST /v1/messages. Both support contact IDs, multiple recipients, and conversation replies. The difference is the request shape.

Two shapes, one pipeline

Underneath, every send Samva performs is a message: recipients, content, and the channel it goes out on, email. The messages API names those parts explicitly. When you call messages.send(), you set channel: "email", list your recipients in to, and nest the email content under email:

import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

await samva.messages.send({
  to: [{ contactId: "contact_k9mvt4znw8rh7q2x" }],
  cc: [{ email: "grace@example.com" }],
  channel: "email",
  email: {
    subject: "Welcome to Samva",
    html: "<h1>Welcome!</h1><p>Thanks for joining.</p>",
    replyTo: "support@example.com",
  },
});

The email.send() facade is the same call in an email-shaped form. It sets the channel for you, flattens the email content up to the top level of the input, and accepts a single recipient or an array. The result is a call that reads like sending an email rather than configuring a generic message:

import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

const result = await samva.email.send({
  to: "ada@example.com",
  cc: "grace@example.com",
  replyTo: "support@example.com",
  subject: "Welcome to Samva",
  html: "<h1>Welcome!</h1>",
});

There is no separate email.send HTTP endpoint. The facade is an SDK-only ergonomic wrapper: it builds the message body shape for you and posts it to POST /v1/messages. From the server's point of view, both snippets above reach the same endpoint. The difference lives entirely in the SDK, in service of the developer reading the code.

Why a facade at all

Most email you send is straightforward. You have an address, a subject, and some HTML, and you want the call site to say exactly that. Forcing every send to spell out channel: "email" and nest content under an email: key adds ceremony to the common case without adding meaning; the channel is obvious when you reached for email.send().

The facade optimizes for that common case. Flattening the email fields directly into the SDK input keeps the simple path short and removes a layer of nesting you would otherwise repeat on every send. It is the canonical way to send a one-off transactional email, and it is what the send an email guide walks through.

The facade supports the email fields available through the messages API, including attachments, contact recipients, cc, bcc, and conversationId. You can keep using email.send() as your email integration grows.

When to use a channel-aware body

Use messages.send() when your application already holds a channel-aware message body, or when code selects the channel and its content together. The method keeps the HTTP request shape visible: channel, recipient arrays, and content under the channel key. For email-specific code, email.send() keeps that same content at the top level.

REST is always the message shape

The split between a facade and the messages API is an SDK convenience. It does not exist over the wire. Every REST integration, whether or not you use the TypeScript SDK, sends to POST /v1/messages using the message body: a channel, a to array, and channel content nested under its key. If you are calling the API directly, there is one shape to learn, and the SDK's email.send() is simply producing that shape on your behalf.

This is why the REST reference and the TypeScript SDK reference can describe the same capability from two angles without contradiction: one documents the endpoint, the other documents the ergonomics layered over it.

Related documentation

On this page