Notifications
Push registration, subscription, and payment events to Telegram, Discord, Slack, or Feishu.
ShipNext operational notifications tell your team about important product events such as new users, subscription changes, and successful payments. They are separate from transactional email sent to end users.
The feature has two layers:
src/integrations/notify/- third-party adapters for Telegram, Discord, Slack, and Feishu.src/modules/notify/- shared types, provider selection, and public handlers.
Business code calls notifyOnUserRegistered, notifyOnUserSubscription, and notifyOnUserPayment. The selected provider comes from websiteConfig.notify.provider.
Notification calls in auth and payment webhooks are commented out by default. Enable them only after configuring provider secrets.
Architecture
| File | Responsibility |
|---|---|
src/modules/notify/types.ts | NotifyProvider interface and event payload types |
src/modules/notify/handler.ts | Public notifyOnUser* APIs |
src/modules/notify/provider.ts | getNotifyProvider() factory |
src/integrations/notify/telegram.ts | Telegram Bot API |
src/integrations/notify/discord.ts | Discord Webhook embeds |
src/integrations/notify/slack.ts | Slack Incoming Webhook |
src/integrations/notify/feishu.ts | Feishu bot cards with optional signing |
Website config
const notifyConfig = {
provider: "telegram", // telegram | discord | slack | feishu
events: {
userRegistered: true,
userSubscription: true,
userPayment: true,
},
};If an event is false, the handler returns early and does not instantiate the provider.
Environment variables
Only configure the provider you use.
| Provider | Variable | Required | Description |
|---|---|---|---|
telegram | TELEGRAM_BOT_TOKEN | Yes | Bot token from BotFather |
telegram | TELEGRAM_CHAT_ID | Yes | Target user, group, or channel ID |
discord | DISCORD_WEBHOOK_URL | Yes | Channel webhook URL |
slack | SLACK_WEBHOOK_URL | Yes | Incoming webhook URL |
feishu | FEISHU_WEBHOOK_URL | Yes | Feishu custom bot webhook |
feishu | FEISHU_SIGNING_SECRET | Optional | Required when signature verification is enabled |
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_CHAT_ID=-1001234567890Provider constructors validate their required variables. Handler errors are caught and logged so registration or payment flows are not interrupted.
Built-in events
| Event | Handler | Typical trigger | Message fields |
|---|---|---|---|
| User registered | notifyOnUserRegistered | Better Auth user create hook | Name, email, user ID |
| Subscription changed | notifyOnUserSubscription | Payment webhook subscription sync | User ID, plan, status, optional interval |
| Payment succeeded | notifyOnUserPayment | Subscription payment or one-time order | User ID, plan/product ID, amount, currency |
Amounts are passed in the smallest currency unit. For USD, 2900 displays as $29.00.
Server usage
import {
notifyOnUserRegistered,
notifyOnUserSubscription,
notifyOnUserPayment,
} from "@/modules/notify/handler";
await notifyOnUserRegistered({
id: user.id,
email: user.email,
name: user.name,
});
await notifyOnUserSubscription({
userId: "user_xxx",
plan: "pro",
status: "active",
interval: "month",
});
await notifyOnUserPayment({
userId: "user_xxx",
amount: 2900,
currency: "usd",
planId: "pro_monthly",
});Enable business hooks
New user registration
In the Better Auth user create hook:
const { notifyOnUserRegistered } = await import("@/modules/notify/handler");
await notifyOnUserRegistered({
id: user.id,
email: user.email,
name: user.name,
});Subscriptions and payments
Search notifyOnUser in src/modules/billing/webhooks/webhook-processor.ts, uncomment the relevant calls, and make sure imports use:
"@/modules/notify/handler"Use your own conditions to avoid duplicate notifications if needed.
Add a provider
- Create a class in
src/integrations/notify/that implementsNotifyProvider. - Export it from
src/integrations/notify/index.ts. - Add a branch in
src/modules/notify/provider.ts. - Add config typing/docs for the new provider value.
- Document required environment variables.
import type { NotifyProvider, NotifyUser } from "@/modules/notify/types";
class MyChannelProvider implements NotifyProvider {
readonly name = "my-channel";
async onUserRegistered(user: NotifyUser): Promise<void> {
// Call third-party API.
}
}Notifications vs email
| Capability | Config | Audience | Examples |
|---|---|---|---|
| Operational notifications | websiteConfig.notify + channel env vars | Your team | Registration, subscription, payment alerts |
| Transactional email | websiteConfig.email + RESEND_API_KEY | End users | Verification, reset password, magic links |
Turning off notifications does not affect email.
Troubleshooting
Configured website.ts but never receive messages
- Confirm the
notifyOnUser*calls are enabled. - Confirm the event switch is
true. - Confirm environment variables match the selected provider.
- Restart the dev server after editing
.env.local.
TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID must be set
The Telegram provider was constructed without required variables. Add them or disable the related event.
Payment webhook has notify: true but no notification
notify: true only marks that a notification should be considered. The webhook processor must call the handler.
Feishu signature verification fails
Set FEISHU_SIGNING_SECRET to the exact secret from the Feishu bot settings.