npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aithreads/sdk

v1.0.0

Published

Official TypeScript/JavaScript SDK for aithreads.io - Email infrastructure for AI agents

Downloads

19

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/sdk

Quick 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-secret

Error 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