Official SDKs

TypeScript and Python clients for the Sending API, generated from the OpenAPI spec.

Two official SDKs are available, both published as sending-sdk. Types (TypeScript) and models (Pydantic) are generated from the v1 OpenAPI spec; the client itself is hand-written for the best developer experience. Both default to https://sending.dev/api/v1.

Installation

npm install sending-sdk
# pnpm add sending-sdk · yarn add sending-sdk

Requirements: Node.js >= 18 (uses native fetch) · Python >= 3.10.

Initialization

The only required parameter is apiKey. The workspace is always derived from the token.

import { Sending } from "sending-sdk";
 
const sending = new Sending({
  apiKey: process.env.SENDING_API_KEY!, // required
  // baseUrl: "http://localhost:3000/api/v1", // optional (dev/self-host)
  // fetch: customFetch,                       // optional (tests/polyfill)
});

Sending

// Transactional email
await sending.emails.send({
  from: "[email protected]",
  to: "[email protected]",
  subject: "Welcome",
  html: "<p>Hi there!</p>",
  idempotencyKey: "welcome-001",
});
 
// Multichannel message (email, WhatsApp, Telegram)
await sending.messages.send({
  channel: "whatsapp",
  to: "+15551234567",
  text: "Hi there!",
  idempotencyKey: "wa-msg-001",
});

Contacts and pagination

const page = await sending.contacts.list({ q: "mario", page: 1, pageSize: 50 });
console.log(page.total, page.data);
 
const { id } = await sending.contacts.create({
  attributes: { firstName: "Mario" },
  identities: [{ channel: "email", address: "[email protected]", consent: "opted_in" }],
});
await sending.contacts.addTag(id, "<tag-uuid>");

Error handling

Non-2xx responses raise SendingError, carrying status, code and body.

import { SendingError } from "sending-sdk";
 
try {
  await sending.emails.send({ /* ... */ } as any);
} catch (err) {
  if (err instanceof SendingError) {
    console.error(err.status, err.code, err.body);
  }
}

Async client (Python)

Same API, on top of httpx.AsyncClient:

import asyncio
from sending import AsyncSending
 
async def main():
    async with AsyncSending(api_key="sk_...") as client:
        await client.emails.send({
            "from": "[email protected]",
            "to": "[email protected]",
            "subject": "Welcome",
            "html": "<p>Hi there!</p>",
            "idempotencyKey": "welcome-001",
        })
 
asyncio.run(main())

Available resources

Both SDKs expose the same surface as the v1 API (in Python, compound names are snake_case, e.g. custom_fields, email_rules):

emails · messages · events · attachments · campaigns · contacts · lists · tags · customFields · segments · domains · inboxes · emailRules · automations · webhooks · utm · integrations · usage.

For attachments the TypeScript SDK has a shortcut that does the signed upload and the confirmation in one step (sending.attachments.upload({ filename, data })); in Python upload_bytes covers small files, and create plus a PUT to uploadUrl covers large ones. See Attachments.

Full schema for every endpoint, required scopes and a "try it" console in the interactive API reference (OpenAPI).