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.
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.
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.
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.
| Adapter | Channel | How it connects |
|---|---|---|
| Resend | Receives on a Resend receiving domain by webhook, sends through Resend. | |
| Microsoft 365 | Reads and sends from a shared mailbox through Microsoft Graph, with change notifications. | |
| Gmail | Google Workspace mailboxes through the Gmail API, with Pub/Sub push or polling. | |
| SMTP / IMAP | Any mailbox. You bring the SMTP transport and IMAP poller for your runtime. | |
| Twilio | SMS & WhatsApp | SMS and WhatsApp through one Twilio number or Messaging Service. |
| WhatsApp Cloud API | Meta's WhatsApp Business Platform directly, including the 24-hour reply window. | |
| Telegram | Chat | A Telegram bot: customers message it, agents answer from the inbox. |
| Signed API | Your forms | Your 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.
- 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.
- 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.
- 03
Automatic mail stays quiet
Out-of-office replies, bounces and mailing lists are kept, but never reopen a ticket or notify anyone.
- 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 stepsnpx 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