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-sdkRequirements: 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.