TypeScript SDK for the Cakemail API.
npm install @cakemail-org/cakemail-sdkimport { CakemailClient } from '@cakemail-org/cakemail-sdk';
// Initialize the client
const client = new CakemailClient({
email: 'your-email@example.com',
password: 'your-password',
});
// Get current account
const account = await client.accounts.getSelf();
console.log('Account:', account);
// List contacts
const contacts = await client.contacts.list({
page: 1,
per_page: 20,
status: 'active',
});
console.log('Contacts:', contacts.data);- đź”’ Automatic Authentication - OAuth 2.0 with automatic token refresh
- 🔄 Retry Logic - Exponential backoff for failed requests
- 📊 Multi-Tenant Support - Manage child accounts seamlessly
- đź’Ş Type-Safe - Full TypeScript support with comprehensive types
- 🎯 User-Friendly Errors - Clear, actionable error messages
- âś… Well Tested - Comprehensive unit test coverage
const client = new CakemailClient({
email: 'your-email@example.com',
password: 'your-password',
});If you already have an access token from an external OAuth flow, you can use it directly:
const client = new CakemailClient({
accessToken: 'your-access-token',
refreshToken: 'your-refresh-token', // Optional but recommended
expiresIn: 3600, // Optional: Token expiration in seconds (default: 3600)
scope: 'read write', // Optional: Token scope (default: 'read write')
});Use cases for access token authentication:
- Web applications with browser-based OAuth flows
- Service accounts with pre-generated tokens
- Integration with external authentication systems
- Token-based authentication without storing passwords
Note: If a refreshToken is provided, the SDK will automatically refresh expired access tokens. Without a refresh token, you'll need to provide a new access token when the current one expires.
const client = new CakemailClient({
email: 'your-email@example.com',
password: 'your-password',
baseURL: 'https://api.cakemail.dev', // Optional: Custom API URL
timeout: 30000, // Optional: Request timeout in ms (default: 30000)
maxRetries: 3, // Optional: Max retry attempts (default: 3)
});// Get current account
const account = await client.accounts.getSelf();
// Get account by ID
const account = await client.accounts.get(123);
// List accounts
const accounts = await client.accounts.list({
page: 1,
per_page: 20,
status: 'active',
});
// Create account
const newAccount = await client.accounts.create({
name: 'New Account',
primary_email: 'new@example.com',
});
// Update account
const updated = await client.accounts.update(123, {
name: 'Updated Name',
});
// Delete account
await client.accounts.delete(123);
// Get child accounts
const children = await client.accounts.getChildren(123);// Get contact by ID
const contact = await client.contacts.get(456);
// Get contact by email
const contact = await client.contacts.getByEmail('user@example.com');
// List contacts
const contacts = await client.contacts.list({
page: 1,
per_page: 20,
status: 'active',
list_id: 789,
});
// Create contact
const newContact = await client.contacts.create({
email: 'new@example.com',
first_name: 'John',
last_name: 'Doe',
custom_attributes: {
company: 'Acme Corp',
},
});
// Update contact
const updated = await client.contacts.update(456, {
first_name: 'Jane',
});
// Delete contact
await client.contacts.delete(456);
// Subscribe to list
await client.contacts.subscribe(456, 789);
// Unsubscribe from list
await client.contacts.unsubscribe(456, 789);
// Add tags
await client.contacts.addTags(456, ['vip', 'newsletter']);
// Remove tags
await client.contacts.removeTags(456, ['newsletter']);
// Bulk operations
const result = await client.contacts.bulkOperation({
contact_ids: [1, 2, 3],
operation: 'subscribe',
parameters: { list_id: 789 },
});// Get list by ID
const list = await client.lists.get(789);
// List all lists
const lists = await client.lists.list({
page: 1,
per_page: 20,
status: 'active',
});
// Create list
const newList = await client.lists.create({
name: 'Newsletter Subscribers',
sender_name: 'Acme Corp',
sender_email: 'newsletter@acme.com',
});
// Update list
const updated = await client.lists.update(789, {
name: 'Updated List Name',
});
// Delete list
await client.lists.delete(789);
// Get list statistics
const stats = await client.lists.getStatistics(789);// Get campaign by ID
const campaign = await client.campaigns.get(101);
// List campaigns
const campaigns = await client.campaigns.list({
page: 1,
per_page: 20,
status: 'sent',
});
// Create campaign
const newCampaign = await client.campaigns.create({
name: 'Monthly Newsletter',
subject: 'Your Monthly Update',
sender_name: 'Acme Corp',
sender_email: 'newsletter@acme.com',
list_ids: [789],
content: {
html: '<h1>Hello!</h1><p>Welcome to our newsletter.</p>',
text: 'Hello! Welcome to our newsletter.',
},
});
// Update campaign
const updated = await client.campaigns.update(101, {
subject: 'Updated Subject Line',
});
// Schedule campaign
await client.campaigns.schedule(101, {
scheduled_at: '2024-12-31T10:00:00Z',
});
// Send campaign immediately
await client.campaigns.send(101);
// Pause campaign
await client.campaigns.pause(101);
// Resume campaign
await client.campaigns.resume(101);
// Cancel campaign
await client.campaigns.cancel(101);
// Get campaign statistics
const stats = await client.campaigns.getStatistics(101);
// Send test email
await client.campaigns.sendTest(101, ['test@example.com']);For parent accounts managing child accounts, you can specify an accountId option:
// Access child account data
const childContacts = await client.contacts.list(
{ status: 'active' },
{ accountId: 456 } // Child account ID
);
// Create resource in child account
const newContact = await client.contacts.create(
{
email: 'new@example.com',
first_name: 'John',
},
{ accountId: 456 }
);The SDK provides detailed error types for better error handling:
import {
CakemailError,
CakemailAPIError,
CakemailAuthError,
CakemailNetworkError,
CakemailValidationError,
} from '@cakemail-org/cakemail-sdk';
try {
const contact = await client.contacts.get(999);
} catch (error) {
if (error instanceof CakemailAPIError) {
console.error('API Error:', error.getUserFriendlyMessage());
console.error('Status Code:', error.statusCode);
console.error('Response:', error.responseBody);
} else if (error instanceof CakemailAuthError) {
console.error('Authentication failed:', error.message);
} else if (error instanceof CakemailNetworkError) {
console.error('Network error:', error.message);
} else if (error instanceof CakemailValidationError) {
console.error('Validation error:', error.message);
}
}API errors include user-friendly messages via getUserFriendlyMessage():
try {
await client.contacts.create({ email: 'invalid-email' });
} catch (error) {
if (error instanceof CakemailAPIError) {
// Shows: "Invalid request: Invalid email format. Please check your parameters."
console.error(error.getUserFriendlyMessage());
}
}The SDK automatically handles OAuth 2.0 token lifecycle:
- Authenticates on first API request
- Caches access tokens
- Refreshes tokens before expiration (5-minute buffer)
- Retries failed requests after token refresh
// Explicitly authenticate (optional)
await client.authenticate();
// Get token information
const tokenInfo = client.getTokenInfo();
console.log('Token valid:', tokenInfo.isValid);
console.log('Expires at:', new Date(tokenInfo.expiresAt!));
// Clear cached token (forces re-authentication)
client.clearAuthCache();The SDK automatically retries failed requests with exponential backoff:
- Network errors: Retries automatically
- 5xx server errors: Retries automatically
- 401 errors: Refreshes token and retries once
- Max retries: 3 attempts (configurable)
- Backoff: 1s, 2s, 4s, 8s (max 10s)
The SDK is written in TypeScript and includes comprehensive type definitions:
import {
Account,
Contact,
List,
Campaign,
CreateContactRequest,
UpdateContactRequest,
ContactStatus,
CampaignStatus,
} from '@cakemail-org/cakemail-sdk';
const contact: Contact = await client.contacts.get(123);
const createRequest: CreateContactRequest = {
email: 'new@example.com',
first_name: 'John',
status: ContactStatus.Active,
};For quick testing, automation scripts, and terminal access, the Cakemail CLI is also available:
Installation:
# via Homebrew (macOS/Linux)
brew tap cakemail/cakemail
brew install cakemail-cli
# via npm
npm install -g @cakemail-org/cakemail-cli
# via npx (no installation)
npx @cakemail-org/cakemail-cli --helpExample usage:
cakemail campaigns list
cakemail contacts create --email user@example.com --first-name John
cakemail campaigns send --id 123The CLI uses this SDK internally and is ideal for:
- Quick testing and debugging
- DevOps automation and CI/CD pipelines
- Non-developer users (marketers, operations teams)
- Scripting and batch operations
See the CLI documentation for complete details.
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverage
# Lint code
npm run lintMIT
- Cakemail CLI - Command-line interface for Cakemail
- Cakemail n8n Node - n8n workflow automation integration
For issues and questions:
- GitHub Issues: https://github.com/cakemail/cakemail-sdk/issues
- Documentation: https://docs.cakemail.com