Odel
tinysend node

tinysend node

@tiny-sendTypeScriptMITUpdated 2mo ago

Email for agents: newsletters, subscribers, contacts, broadcasts. OAuth sign-in, no API key.

View on GitHub
Server endpointStreamable HTTPOAuthProbed

This is the third-party server itself — Odel doesn't run it. Hitting this URL directly talks straight to the upstream server with no auth or proxying. Connect through Odel to front it with managed auth.

tinysend

Official TypeScript SDK for the tinysend API. Zero dependencies, fetch-based — works in Node.js, Bun, Deno, Cloudflare Workers, and browsers.

subscribers

Install

npm install tinysend

Getting a token

Every call needs a bearer token (sk_...).

Usage

import { Tinysend } from 'tinysend';

const ts = new Tinysend('sk_...');

// lists
const lists = await ts.lists.list();
const list = await ts.lists.create({ name: 'Weekly Update' });

// subscribers
await ts.subscribers.create(list.id, { email: 'user@example.com', verified: true });

// send an email
const post = await ts.posts.create(list.id, {
  subject: 'Hello World',
  body_html: '<p>Welcome to our newsletter!</p>',
});
await ts.posts.send(list.id, post.id);

// contacts
const contacts = await ts.contacts.list({ search: 'john' });

// mailboxes
const mailboxes = await ts.mailboxes.list();

// stats
const stats = await ts.stats.project();

// webhooks
const hook = await ts.webhooks.create({
  url: 'https://example.com/webhook',
  events: ['post.sent', 'subscriber.created'],
});

// sender domain (who emails come from)
await ts.sender.set(list.id, { type: 'custom_domain', name: 'James', email: 'james', domain: 'acme.com' });
await ts.sender.check(list.id); // re-check DNS

// custom domain for the archive site
await ts.siteDomains.set(list.id, { domain: 'news.acme.com' });

// waitlists
await ts.lists.join(list.id, { email: 'user@example.com' });
await ts.lists.invite(list.id, { count: 100 });

// automations, invites, usage, settings
const automations = await ts.automations.list();
const invites = await ts.invites.list();
const usage = await ts.usage.get();

The SDK covers the full API surface — verified against the live openapi spec on every release.

Error handling

import { Tinysend, TinysendError } from 'tinysend';

try {
  await ts.lists.get('nonexistent');
} catch (err) {
  if (err instanceof TinysendError) {
    console.log(err.status);  // 404
    console.log(err.code);    // 'not_found'
    console.log(err.message); // 'list not found'
  }
}

Configuration

const ts = new Tinysend('sk_...', {
  baseUrl: 'https://api.tinysend.com/v1',  // default
  fetch: customFetch,                        // custom fetch implementation
});

License

MIT


a system operator product