Node.js / TypeScript SDK
Official Node.js SDK for the Tratto Email API
The official SDK for Node.js and TypeScript: @tratto/email
Every example on this page is written against the published 1.1.0 release and typechecks against it.
Installation
npm install @tratto/emailInitialization
The exported class is Tratto, and the API key is a positional argument,
not an options object:
import { Tratto } from '@tratto/email';
const tratto = new Tratto(process.env.TRATTO_API_KEY!);An optional second argument overrides the base URL:
const tratto = new Tratto(process.env.TRATTO_API_KEY!, {
baseUrl: 'https://api.tratto.email',
});Send Email
emails.send resolves to { id } — nothing else. To read the status, fetch
the email back.
const { id } = await tratto.emails.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Hello!',
text: 'Welcome to Tratto',
html: '<h1>Welcome!</h1>',
});
console.log(id); // email_abc123Pass an idempotency key as the second argument:
await tratto.emails.send(
{ from: '[email protected]', to: '[email protected]', subject: 'Hi', text: 'Hi' },
'order-4711-confirmation',
);Send with Template
const { id } = await tratto.emails.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome, Alice!',
templateId: 'tmpl_abc123',
variables: {
firstName: 'Alice',
code: 'SECRET123',
},
});subject is required on every send, template or not. A template carries no
subject of its own — see Templates.
Send with Markdown
Send Markdown and let the server render
responsive email HTML — markdown is mutually exclusive with html:
const { id } = await tratto.emails.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome!',
markdown: '# Welcome, {{firstName}}!',
variables: { firstName: 'Alice' },
});templates.create and templates.update take markdown too, and the
Template response type carries format, source and renderWarnings.
Schedule Email
const { id } = await tratto.emails.send({
from: '[email protected]',
to: '[email protected]',
subject: 'Reminder',
text: 'See you tomorrow!',
scheduledAt: new Date('2026-10-01T09:00:00Z'),
});Canceling or rescheduling a scheduled email is available over HTTP but has no SDK method yet — see What 1.1.0 does not cover.
Get Email Status
const email = await tratto.emails.get('email_abc123');
console.log(email.status); // 'delivered'
console.log(email.events); // full timelineList Emails
const emails = await tratto.emails.list({
limit: 50,
after: 'cursor_value', // for pagination
});
emails.data.forEach((email) => {
console.log(`${email.id}: ${email.status}`);
});Add a Domain
The method is add, and it takes the domain as a string:
const domain = await tratto.domains.add('hello.yourdomain.com');
// `records` is an array of DNS records, not an object keyed by type
for (const record of domain.records) {
console.log(`${record.type} ${record.host} → ${record.value}`);
}Verify Domain
const verified = await tratto.domains.verify('dom_abc123');
console.log(verified.status); // 'pending' | 'verified' | 'failed'Create Contact
Custom properties live in customFields. There is no metadata field:
const { id } = await tratto.contacts.create({
email: '[email protected]',
firstName: 'Alice',
lastName: 'Smith',
tags: ['vip', 'newsletter'],
customFields: { plan: 'pro' },
});Create Campaign
CreateCampaignParams in 1.1.0 requires templateId, audienceId,
fromName, fromEmail and subjectA. create resolves to { id }:
const { id } = await tratto.campaigns.create({
name: 'Q3 Sale',
templateId: 'tmpl_abc123',
audienceId: 'aud_abc123',
fromName: 'Acme',
fromEmail: '[email protected]',
subjectA: 'Our summer sale starts today',
subjectB: 'Summer sale: 30% off, today only', // optional A/B subject
});
const campaign = await tratto.campaigns.get(id);
console.log(campaign.status); // 'draft'The API itself is more permissive than the 1.1.0 types: it accepts inline
html instead of a templateId, and treats an omitted audienceId as "every
contact in the workspace". Neither is expressible through the SDK yet — use
HTTP for those.
Send Campaign
const sent = await tratto.campaigns.send('camp_xyz789');
console.log(sent.status); // 'sending'Schedule it instead by passing a date:
await tratto.campaigns.send('camp_xyz789', {
scheduledAt: new Date('2026-10-01T09:00:00Z'),
});Get Campaign Stats
The method is getStats. Rates are percentages: 50 means 50%, not
0.5 — the same scale as Analytics.
const stats = await tratto.campaigns.getStats('camp_xyz789');
console.log(stats.stats.delivered); // 4950
console.log(stats.rates.openRate); // 50 → 50%
console.log(stats.rates.deliveryRate) // 99 → 99%An alert written as rates.deliveryRate < 0.95 will never fire. The
comparison you want is < 95.
Register Webhook
const webhook = await tratto.webhooks.create({
url: 'https://yourapi.com/webhooks/tratto',
events: ['sent', 'delivered', 'opened', 'clicked', 'bounced'],
});
console.log(webhook.secret); // whsec_xyz789...Analytics
AnalyticsPeriod in 1.1.0 is '7d' | '30d' | '90d':
const summary = await tratto.analytics.getSummary('30d');
console.log(summary.delivered);The API also accepts 180d and 1y; those two are not in the SDK type yet,
so reach for HTTP if you need them.
Error Handling
TrattoError carries code, statusCode and docs:
import { Tratto, TrattoError } from '@tratto/email';
const tratto = new Tratto(process.env.TRATTO_API_KEY!);
try {
await tratto.emails.send({
from: '[email protected]', // not verified
to: '[email protected]',
subject: 'Hello',
text: 'Test',
});
} catch (error) {
if (error instanceof TrattoError) {
// The message names the domain that is not verified.
console.error(error.code, error.statusCode, error.message);
}
}See Error Codes for the full list.
What 1.1.0 does not cover yet
These endpoints exist in the API and have no SDK method in 1.1.0. Call them over HTTP until the SDK catches up:
| Capability | HTTP |
|---|---|
| Cancel a scheduled email | DELETE /v1/emails/{id} |
| Reschedule an email | PATCH /v1/emails/{id} |
| Get one contact | GET /v1/contacts/{id} |
| Update / delete a campaign | PATCH, DELETE /v1/campaigns/{id} |
| Unschedule a campaign | POST /v1/campaigns/{id}/unschedule |
| Campaign link clicks | GET /v1/campaigns/{id}/links |
| Update / delete / refresh an audience | PATCH, DELETE, POST …/refresh on /v1/audiences/{id} |
| List or remove audience contacts | GET, DELETE on /v1/audiences/{id}/contacts |
| Render a markdown preview | POST /v1/templates/render-preview |
| API key management | /v1/api-keys |
| Workspace brand logo | PUT, DELETE /v1/workspace/brand/logo |
Some newer response fields are likewise absent from the 1.1.0 types:
Workspace has no limits or brand, Contact has no trackingOptOut,
ListContactsParams has no q, and CampaignStats has no skipped,
untracked or variants. The API returns them; the types do not describe
them yet.
Links
- npm: https://www.npmjs.com/package/@tratto/email
- GitHub: https://github.com/tratto-email/tratto-node
- API Docs: API Reference
Edit this page on GitHub
Last updated on