Docs · SDKs

TypeScript SDK

A zero-dependency typed client for Node 20+.

The TypeScript client is the npm package agentboxd (source under sdk/ in the Mailroom repo). It has no dependencies: it uses the global fetch and node:crypto, and needs Node 20 or newer.

client.ts
import { Agentboxd } from 'agentboxd';

const mr = new Agentboxd({ apiKey: process.env.MAILROOM_API_KEY!, baseUrl: 'https://api.agentboxd.com' });

#Methods

CallEndpoint
mr.inboxes.create({ username?, display_name?, client_id? })POST /v1/inboxes
mr.inboxes.list() · get(id) · delete(id)/v1/inboxes
mr.inboxes.createTemporary({ ttlSeconds })POST /v1/inboxes with ttl_seconds
mr.domains.create/list/get/verify/update/delete/v1/domains
mr.messages.send(inboxId, { to, subject, text?, html?, attachments? }, { idempotencyKey? })POST …/messages/send
mr.messages.reply(inboxId, messageId, { text?, html?, reply_all? })POST …/reply
mr.messages.list(inboxId, { labels?, is_read?, direction? })GET …/messages
mr.messages.wait(inboxId, { timeout?, since?, from?, subject? })GET …/messages/wait
mr.messages.waitForVerification(inboxId, { timeout?, since?, from? })GET …/verification
mr.messages.get(id) · update(id, { add_labels?, remove_labels?, is_read? })/v1/messages/:id
mr.threads.list(inboxId) · get(id)/v1/…/threads
mr.search(q, { inbox_id? })GET /v1/search
mr.inboxes.update(id, { display_name?, metadata? })PATCH /v1/inboxes/:id
mr.threads.update(id, { metadata?, add_labels?, remove_labels? })PATCH /v1/threads/:id
mr.contacts.list({ q?, label?, metadata? }) · get(id) · byAddress(address)/v1/contacts
mr.contacts.update(id, { name?, notes?, metadata?, add_labels?, remove_labels? })PATCH /v1/contacts/:id
mr.knowledge.list/create/get/update/delete/v1/knowledge
mr.knowledge.search(q, { inbox_id?, limit? })GET /v1/knowledge/search
mr.messages.draftReply(id, { instructions? })POST /v1/messages/:id/draft-reply
mr.webhooks.create/list/get/update/delete/test/v1/webhooks

#Contacts and knowledge

contacts.ts
// Who is this? Name, notes, metadata and labels, created from mail.
const c = await mr.contacts.byAddress('priya.n@gmail.com');
console.log(c.notes, c.metadata.crm_id); // "Wholesale…" "hs_48213"

// Link it to your CRM and remember something. Metadata merges; null deletes a key.
await mr.contacts.update(c.id, {
  notes: `${c.notes ?? ''}
Asked about order 1042 on 25 Sep.`,
  metadata: { crm_id: 'hs_48213', plan: 'wholesale' },
  add_labels: ['customer'],
});

// Find contacts by your own id.
const { data } = await mr.contacts.list({ metadata: { crm_id: 'hs_48213' } });
knowledge.ts
// Workspace-wide (no inbox_id) or for one inbox.
await mr.knowledge.create({
  title: 'Shipping times',
  body: '- Germany: 1–2 working days (DHL)
- EU: 3–5 working days',
  inbox_id: inbox.id,
});

// Ranked full-text search. With inbox_id, workspace-wide documents are included too.
const { data: hits } = await mr.knowledge.search('how long does shipping to France take', { inbox_id: inbox.id });
// [{ id, title: 'Shipping times', inbox_id, rank: 0.61, snippet: '…EU: 3–5 working days…' }]

#Errors

Non-2xx responses throw AgentboxdError (also exported as MailroomError) with status, code and message from the API’s error body.

errors.ts
import { AgentboxdError } from 'agentboxd';

try {
  await mr.messages.send(inbox.id, { to: 'x@example.com', subject: 'Hi', text: '…' });
} catch (e) {
  if (e instanceof AgentboxdError && e.code === 'daily_send_limit_exceeded') {
    // back off until 00:00 UTC
  }
}

#Webhook verification

verifyWebhook(signature, timestamp, rawBody, secret, { toleranceSeconds? }) returns a boolean. See Webhooks for a full Express example.