@aithreads/sdk
v1.0.0
Published
Official TypeScript/JavaScript SDK for aithreads.io - Email infrastructure for AI agents
Downloads
19
Maintainers
Readme
@aithreads/sdk
Official TypeScript/JavaScript SDK for aithreads.io - Email infrastructure for AI agents.
Installation
npm install @aithreads/sdk
# or
pnpm add @aithreads/sdk
# or
yarn add @aithreads/sdkQuick Start
import { AIThreadsClient } from '@aithreads/sdk';
const client = new AIThreadsClient({
apiKey: 'ait_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
});
// Get an inbox by email address
const inbox = await client.inboxes.get('[email protected]');
// Send an email (simplified syntax)
await inbox.send({
to: '[email protected]',
subject: 'Hello from AI',
text: 'This is a test email from my AI agent.',
});
// Get threads and reply
const threads = await inbox.getThreads({ is_read: false });
const thread = threads.data[0];
const messages = await thread.getMessages();
await thread.reply({ text: 'Thanks for reaching out!' });
await thread.markAsRead();Features
- 📬 Inbox Management: Create and manage email inboxes for your AI agents
- 📧 Email Operations: Send and receive emails with full threading support
- 🧵 Thread Management: Organize conversations with automatic threading
- 🏷️ Labels: Categorize threads with custom labels
- 📚 Knowledge Base: Upload documents for AI context
- 🔍 Search: Find threads by participant email address
- 🔐 Webhook Verification: Cryptographic signature verification for webhooks
- ⚡ TypeScript First: Full type safety with comprehensive types
- 🎯 Fluent API: Chainable, intuitive methods on inbox and thread objects
API Reference
Client Initialization
import { AIThreadsClient, VERSION } from '@aithreads/sdk';
console.log('SDK Version:', VERSION); // e.g., "1.0.0"
const client = new AIThreadsClient({
apiKey: 'ait_...', // Required: Your API key
baseUrl: 'https://...', // Optional: API base URL (default: https://api.aithreads.io/v1)
timeout: 30000, // Optional: Request timeout in ms (default: 30000)
retries: 3, // Optional: Number of retries (default: 3)
});Inboxes (Fluent API)
// Get inbox by email address or ID
const inbox = await client.inboxes.get('[email protected]');
// or
const inbox = await client.inboxes.get('inbox-uuid');
// Send email directly from inbox (simplified syntax)
await inbox.send({
to: '[email protected]', // String, array of strings, or objects
subject: 'Hello',
text: 'Plain text body',
html: '<p>HTML body</p>', // Optional
cc: ['[email protected]'], // Optional
bcc: [{ email: '[email protected]' }], // Optional
});
// Get threads from inbox
const threads = await inbox.getThreads({
is_read: false,
is_archived: false,
labels: ['important'],
participant: '[email protected]',
limit: 20,
offset: 0,
});
// Get a specific thread
const thread = await inbox.getThread('thread-uuid');
// Update inbox
await inbox.update({
display_name: 'Support Agent',
agent_prompt: 'You are a helpful support agent...',
});
// Delete inbox
await inbox.delete();Threads (Fluent API)
const threads = await inbox.getThreads({ is_read: false });
const thread = threads.data[0];
// Get all messages in a thread
const messages = await thread.getMessages();
// Reply to thread (sends to all participants)
await thread.reply({
text: 'Thanks for your email!',
html: '<p>Thanks for your email!</p>',
cc: '[email protected]', // Optional
});
// Thread actions
await thread.markAsRead();
await thread.markAsUnread();
await thread.archive();
await thread.unarchive();
// Manage labels
await thread.addLabels(['urgent', 'follow-up']);
await thread.removeLabels(['urgent']);
await thread.update({ labels: ['resolved'] });
// Delete thread
await thread.delete();Traditional API (Still Available)
// List all inboxes
const inboxes = await client.inboxes.list();
// Create an inbox
const inbox = await client.inboxes.create({
username: 'support',
name: 'Support Agent',
webhook_url: 'https://example.com/webhook',
});
// Update inbox by ID
await client.inboxes.update('inbox-id', {
display_name: 'Updated Name',
});
// Thread operations by ID
const threads = await client.threads.list('inbox-id', {
limit: 20,
is_read: false,
});
await client.threads.markAsRead('inbox-id', 'thread-id');
await client.threads.archive('inbox-id', 'thread-id');
// Send email by inbox ID
await client.emails.send('inbox-id', {
to: [{ email: '[email protected]', name: 'User' }],
subject: 'Hello',
text: 'Message body',
});Labels
// Organization-level labels
const labels = await client.labels.list();
const label = await client.labels.create({
name: 'Important',
color: '#FF5733',
description: 'High priority items',
});
await client.labels.update('label-id', { color: '#00FF00' });
await client.labels.delete('label-id');
// Inbox-specific labels
const inboxLabels = await client.inboxLabels.list('inbox-id');
await client.inboxLabels.create('inbox-id', {
name: 'Resolved',
color: '#00FF00',
});Documents (Knowledge Base)
// List documents
const docs = await client.documents.list('inbox-id');
// Upload a document (browser)
const file = new File(['content'], 'document.txt', { type: 'text/plain' });
await client.documents.upload('inbox-id', file, 'My Document');
// Search documents
const results = await client.documents.search('inbox-id', 'refund policy');
// Get AI context from documents
const context = await client.documents.getContext('inbox-id', 'How do I process refunds?', 5);
// Delete document
await client.documents.delete('inbox-id', 'doc-id');Webhook Verification
When you set up a webhook URL for an inbox, AIThreads signs all webhook payloads so you can verify they're authentic:
import { constructWebhookEvent, verifyWebhookSignature } from '@aithreads/sdk';
// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = constructWebhookEvent(
req.body,
req.headers,
process.env.WEBHOOK_SECRET!
);
console.log(`Received ${event.event} for email ${event.email_id}`);
// Handle the event
switch (event.event) {
case 'email.received':
// Process incoming email
break;
}
res.json({ received: true });
} catch (error) {
console.error('Webhook verification failed:', error.message);
res.status(401).json({ error: 'Invalid signature' });
}
});Verification Options
import { verifyWebhookSignature, verifyWebhook } from '@aithreads/sdk';
// Option 1: Get result object (doesn't throw)
const result = verifyWebhookSignature(payload, signature, secret, {
maxAge: 300, // Max age in seconds (default: 5 minutes)
});
if (result.valid) {
console.log('Event:', result.payload.event);
} else {
console.error('Error:', result.error);
}
// Option 2: Throws on failure
try {
const payload = verifyWebhook(body, signature, secret);
console.log('Event:', payload.event);
} catch (error) {
console.error('Invalid:', error.message);
}Webhook Payload
interface WebhookPayload {
event: 'email.received' | 'email.sent' | 'thread.created';
email_id: string;
thread_id: string;
inbox_id: string;
subject: string;
from: string;
timestamp: string; // ISO 8601
}Getting Your Webhook Secret
When you create an inbox with a webhook URL, a webhook secret is automatically generated. You can retrieve or regenerate it:
// Create inbox with webhook
const inbox = await client.inboxes.create({
username: 'support',
webhook_url: 'https://example.com/webhook',
});
// The webhook_secret is returned on creation
// Regenerate webhook secret (via API)
// POST /v1/organizations/:org_id/inboxes/:inbox_id/webhook-secretError Handling
The SDK provides typed errors with type guards for easy handling:
import {
AIThreadsError,
NotFoundError,
PaymentRequiredError,
RateLimitError,
// Type guards
isNotFoundError,
isPaymentRequiredError,
isRateLimitError,
} from '@aithreads/sdk';
try {
await inbox.send({ to: '[email protected]', subject: 'Hi', text: 'Hello' });
} catch (error) {
// Using type guards (recommended)
if (isNotFoundError(error)) {
console.log('Inbox not found');
} else if (isPaymentRequiredError(error)) {
console.log(`Upgrade required. Current plan: ${error.plan}`);
} else if (isRateLimitError(error)) {
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
}
// Or using instanceof
if (error instanceof AIThreadsError) {
console.log(`Error: ${error.message} (${error.code})`);
console.log(`Status: ${error.status}`);
console.log(`Details:`, error.details);
}
}Error Types
| Error | Status | Description |
|-------|--------|-------------|
| ValidationError | 400 | Invalid request data |
| AuthenticationError | 401 | Invalid or missing API key |
| PaymentRequiredError | 402 | Plan limits exceeded or subscription issue |
| ForbiddenError | 403 | Permission denied |
| NotFoundError | 404 | Resource not found |
| ConflictError | 409 | Resource conflict (e.g., duplicate) |
| RateLimitError | 429 | Too many requests |
| ServerError | 5xx | Server-side error |
TypeScript Support
All types are exported for full TypeScript support:
import type {
// Inbox types
Inbox,
InboxResponse,
InboxInstance,
SimpleSendEmailOptions,
// Thread types
Thread,
ThreadResponse,
ThreadInstance,
ThreadReplyOptions,
// Email types
Email,
SendEmailRequest,
SendEmailResponse,
// Webhook types
WebhookPayload,
WebhookEventType,
VerifyWebhookOptions,
WebhookVerificationResult,
// Common types
PaginatedResponse,
Label,
} from '@aithreads/sdk';Requirements
- Node.js 18+
- Modern browser with Fetch API support
License
MIT
