Tendkit

Customer support, inside your own app.

Turn customer emails, WhatsApp and SMS into tickets your team answers right next to the customer's account. You copy the code into your app, so it's yours: no seats, no vendor, no data leaving your database.

MIT licensed · Runs in production at Moosyl and Moorsyl

It looks like your app, because it is.

The screens are built from your shadcn/ui components and theme tokens. Pick a theme below: this is the real ticket screen, running in your browser. Reply, and the customer writes back.

Color
Radius
Font
Mode
AAcmeAC

Every ticket knows its customer.

One small directory tells Tendkit who wrote: which user, which account. Tickets then sit beside your own data (plan, orders, payments), and a sender you don't recognize is linked once, by hand, for good.

lib/support/directory.ts
const directory: SupportDirectory = {
  // Who wrote? Match the sender to your users and accounts.
  async identify({ value: email }) {
    const user = await findUserByEmail(email);
    if (!user) return null;
    return {
      customerId: user.accountId,
      userId: user.id,
      name: user.name,
    };
  },
  searchCustomers: (q) => searchAccounts(q),
  getCustomers: (ids) => getAccounts(ids),
  listAgents: () => listAdmins(),
};

Every channel, one inbox.

Each adapter is one file with no SDK: plain fetch and WebCrypto, so it runs on Cloudflare Workers, Node, Bun and Deno. Tickets live in Postgres or SQLite/D1.

AdapterHow it connects
ResendReceives on a Resend receiving domain by webhook, sends through Resend.
Microsoft 365Reads and sends from a shared mailbox through Microsoft Graph, with change notifications.
GmailGoogle Workspace mailboxes through the Gmail API, with Pub/Sub push or polling.
SMTP / IMAPAny mailbox. You bring the SMTP transport and IMAP poller for your runtime.
TwilioSMS and WhatsApp through one Twilio number or Messaging Service.
WhatsApp Cloud APIMeta's WhatsApp Business Platform directly, including the 24-hour reply window.
TelegramA Telegram bot: customers message it, agents answer from the inbox.
Signed APIYour contact form or app posts signed requests; replies go out by email.

Missing one? Adapters are a single file. Pick one up on GitHub.

Email that behaves like email.

The parts that make a support inbox hard, handled and tested.

  1. 01

    Replies thread in the customer's mail client

    In-Reply-To and References headers, plus a reply address carrying a ticket token, so answers find the right ticket even when a client drops the headers.

  2. 02

    Only what they wrote this time

    Quoted history and signatures are trimmed, in English, French and Arabic. The full message is one click away.

  3. 03

    Automatic mail stays quiet

    Out-of-office replies, bounces and mailing lists are kept, but never reopen a ticket or notify anyone.

  4. 04

    Spoofed senders stay strangers

    Mail that fails DMARC, or both SPF and DKIM, is never matched to an account and never gets an automatic reply. If it's real, a person links it.

Copied in, not installed.

Tendkit is a shadcn registry, not a package. The CLI copies the inbox, the engine and the adapters you pick into your repo, where they use your components and your database. Take upstream fixes with a diff, when you want them.

Set it up in six steps
Terminal
npx shadcn@latest add \
  https://tendkit.softwaresavants.dev/r/support.json \
  https://tendkit.softwaresavants.dev/r/support-postgres.json \
  https://tendkit.softwaresavants.dev/r/support-ui.json \
  https://tendkit.softwaresavants.dev/r/channel-resend.json

Give your customers an inbox that's yours.