# Moving to the Cowliss SDK

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

The facade exists so you can start without touching your sending code. This page is the other end: what adopting `@cowliss/sdk` actually changes, and what it does not.

The short version: both calls reach the same send service, so everything around the message (your domain, your suppression list, your delivery rows, your credit) is unaffected. What you gain is the rest of Cowliss, which the Resend shape has nowhere to express.

## The two calls, side by side

```ts
// The facade: Resend's SDK, Resend's field names.
await resend.emails.send({
  from: "Acme <hello@acme.com>",
  to: ["ada@acme-demo.io"],
  reply_to: "support@acme.com",
  template: { id: "receipt", variables: { orderId: "A-2291" } },
});
// → { id: "dlv_…" }
```

```ts
// Cowliss: camelCase, and the app comes from the client.
const { deliveryId } = await cow.emails.send({
  from: "Acme <hello@acme.com>",
  to: "ada@acme-demo.io",
  replyTo: "support@acme.com",
  template: { key: "receipt", props: { orderId: "A-2291" } },
});
// → { deliveryId: "dlv_…" }
```

| The facade | Cowliss | Note |
| --- | --- | --- |
| The app id in `RESEND_BASE_URL` | `sourceId` on the client | The Resend SDK has no field for it, so the facade puts it in the path. Same pipe either way. |
| `reply_to` | `replyTo` | Every field is camelCase. |
| `template: { id, variables }` | `template: { key, props }` | The same pushed template, renamed to what the rest of Cowliss calls it. |
| `to` as an address or an array | Unchanged | Both take one address or up to 50. |
| `tags` | Not taken | Accepted and dropped by the facade; Cowliss tags a delivery by its own fields. |
| `{ id }` | `{ deliveryId }` | The same id, which is the [delivery](/emails/delivery/) row. |
| `{ statusCode, message, name }` | `{ error: { code, message } }` | Cowliss errors follow the [shared envelope](/api-conventions/#errors). |

The full field list is on [`emails.send`](/sdk/emails/).

## What the facade cannot express

- **Automations.** Resend's shape has one verb, send now. No wait, no branch, no enrollment, and no cancelling a message because the person did the thing in the meantime. That is the whole of [automations](/automations/).
- **Templates by key only.** The facade names a pushed template and passes variables. It has no way to preview one, test one, or read what it rendered.
- **`Idempotency-Key` on a batch.** A single send honours the header and replays the first successful answer; a failed send frees its key. A batch ignores it: a retried batch is a second batch.
- **A profile.** The facade takes addresses only, and an address carries no consent and no frequency cap, which is why a template its recipients can turn off is refused when it goes to one. `cow.emails.send` can address a profile (`to: { userId: "shop_1" }`), checks its consent and carries the unsubscribe links. Resend's shape has nowhere to put one.
- **`attachments`, `scheduled_at`, `topic_id`** and the domains, api-keys, audiences, contacts and broadcasts resources are not served at all.

## What carries over untouched

Both paths call the same send service, so none of this is re-verified when you switch:

- **Your sending domain.** The same verified-domain check refuses the same `from`.
- **Your suppression list.** A bounced or complained address is dropped from either call.
- **Your delivery log.** The same rows, the same `dlv_` ids, the same statuses, in [Deliveries](/emails/delivery/) beside everything your automations send.
- **Your credit and rate limit.** One meter for both.
- **Your templates.** The same version, module or doc, rendered by the same renderer as the Send test on the template's page.

## Both at once

They can run side by side: same organization, same key, same app. The facade resolves the app from the URL and the SDK from the client's `sourceId`, and both write deliveries of the same kind against the same source. So a migration is per call site, not a cutover: move the sends you are touching anyway, leave the rest, and nothing in the delivery log tells them apart.
