Samva is in early access — self-serve signup is limited. Have a team invite? Sign up with that email. Contact us for access.

Samva

Email and the unified API

Why Samva exposes both an email-first send facade and a unified messages API, and how the design keeps the email path stable while leaving room for staged channels.

Samva gives you two ways to send email: a small, email-shaped email.send() facade and a broader messages.send() API that maps directly onto POST /v1/messages. They are not competing products or different transports — they are two views of the same send pipeline. This page explains why both exist, how they relate, and what that design buys you over time.

Email first. Samva is launching with email. SMS, WhatsApp, and voice are staged and will be documented as they ship.

Two shapes, one pipeline

Underneath, every send Samva performs is a message: a piece of content, a recipient, and a channel that carries it. The unified API names those parts explicitly. When you call messages.send(), you declare the channel, list your recipients in to, and nest the channel-specific content under a matching key:

await samva.messages.send({
  to: [{ contactId: "contact_123" }],
  channel: "email",
  email: {
    subject: "Welcome to Samva",
    html: "<h1>Welcome!</h1><p>Thanks for joining.</p>",
  },
});

The email.send() facade is the same call wearing email-shaped clothes. It assumes the channel is email, 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:

const result = await samva.email.send({
  to: "ada@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 unified body shape for you and posts it to POST /v1/messages. From the server's point of view, both snippets above are the same request to 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.

That convenience is deliberately narrow. The facade does not hide the unified API or replace it — it sits on top of it. When your needs outgrow "one address, one subject, one body," you drop down to the API the facade was built on, and nothing about the underlying send changes.

When to reach for the unified API

Reach for messages.send() (or POST /v1/messages directly) when the send is no longer a single self-contained email:

  • Addressing existing contacts. The unified to array accepts { contactId }, so you can send to a contact you already store in Samva without re-supplying their email address.
  • Multiple recipients. When you are addressing a list rather than one person, the array form of to is the natural fit.
  • Threading a reply. When a send belongs to an existing conversation, the unified body is where you express that relationship so the message lands in the right thread.

The dividing line is conceptual, not performance- or feature-based: the facade is for "send this email to this address," and the unified API is for everything that needs to talk about messages, recipients, contacts, and conversations as first-class things. Because the facade compiles down to the same request, you can start with email.send() and move to messages.send() later without rethinking how your email is delivered.

REST is always the unified shape

The split between a facade and a unified 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 unified 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 unified endpoint, the other documents the ergonomics layered over it.

Room for staged channels

The word "unified" in the unified API is forward-looking. Modeling a send as a channel plus channel-specific content is what lets Samva add channels without reworking the parts that are already stable. Today channel: "email" is the only value you would use; the email: {...} block carries the subject, HTML, and text. Tomorrow, a new channel slots in as another channel value with its own content block, addressed through the same to array and the same POST /v1/messages endpoint.

Crucially, that growth does not touch the email path. The email.send() facade is pinned to email by definition, so adding SMS, WhatsApp, or voice cannot change how it behaves, what fields it takes, or what it sends. Email-first code written today keeps working unchanged as the platform's channel set grows. The unified shape absorbs the new channels; the email facade stays exactly as small as it is now.

This is the tradeoff the two-API design resolves. A single generic API would make every email verbose. A single email-only API would have no room to grow. By offering the facade for the common case and the unified API as its foundation, Samva keeps the simple thing simple while leaving the model open — and keeps the staged channels a future addition rather than a future migration.

On this page