Quick Start

Minimal, copy-paste-ready examples for each channel. All examples assume you have completed the Getting Started setup.


Using Statements

All code examples use these namespaces:

using RecurPixel.Notify;                    // INotifyService, TriggerResult, NotifyContext, NotifyUser
using RecurPixel.Notify.Channels;           // INotificationChannel
using RecurPixel.Notify.Configuration;      // Channel options

Email

// appsettings.json
"Email": {
  "Provider": "sendgrid",
  "SendGrid": { "ApiKey": "SG.xxx", "FromEmail": "no-reply@yourapp.com", "FromName": "Your App" }
}
// Orchestrated send
await notify.TriggerAsync("any.event", new NotifyContext
{
    User = new NotifyUser { Email = "user@example.com" },
    Channels = new() { ["email"] = new() { Subject = "Hello", Body = "<p>Hello world</p>" } }
});

// Direct send — no orchestrator needed
await notify.Email.SendAsync(new NotificationPayload
{
    To      = "user@example.com",
    Subject = "Hello",
    Body    = "<p>Hello world</p>"
});

SMS

Twilio:

"Sms": {
  "Provider": "twilio",
  "Twilio": { "AccountSid": "ACxxx", "AuthToken": "xxx", "FromNumber": "+15550001234" }
}

MSG91:

"Sms": {
  "Provider": "msg91",
  "Msg91": { "AuthKey": "xxxxxxxxxxxxxxxxxxxxxxxxxx", "SenderId": "NOTIFY", "Route": "4" }
}
await notify.Sms.SendAsync(new NotificationPayload
{
    To   = "919876543210",   // digits only, no + prefix for MSG91
    Body = "Your OTP is 482910. Valid for 5 minutes."
});

Push (FCM)

"Push": {
  "Provider": "fcm",
  "Fcm": { "ProjectId": "my-project", "ServiceAccountJson": "{ ... full JSON ... }" }
}
await notify.Push.SendAsync(new NotificationPayload
{
    To      = "device-registration-token",
    Subject = "New message",
    Body    = "You have a new message from Alex."
});

WhatsApp

Twilio:

"WhatsApp": {
  "Provider": "twilio",
  "Twilio": { "AccountSid": "ACxxx", "AuthToken": "xxx", "FromNumber": "whatsapp:+14155238886" }
}
await notify.WhatsApp.SendAsync(new NotificationPayload
{
    To   = "whatsapp:+919876543210",   // whatsapp: prefix required for Twilio
    Body = "Your order has been dispatched."
});

MSG91:

"WhatsApp": {
  "Provider": "msg91",
  "Msg91": {
    "AuthKey": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "IntegratedNumber": "919876543210",
    "Namespace": "your-waba-namespace"
  }
}
await notify.WhatsApp.SendAsync(new NotificationPayload
{
    To   = "919876543210",   // digits only, no + prefix for MSG91
    Body = "Your order has been dispatched."
});

Slack

"Slack": { "WebhookUrl": "https://hooks.slack.com/services/T00/B00/xxx" }
await notify.Slack.SendAsync(new NotificationPayload
{
    Subject = "Alert",
    Body    = "Payment gateway error rate exceeded 5% in the last 10 minutes."
});

Discord

"Discord": { "WebhookUrl": "https://discord.com/api/webhooks/xxx/yyy" }
await notify.Discord.SendAsync(new NotificationPayload
{
    Body = "New deployment to production — v2.4.1"
});

Teams

"Teams": { "WebhookUrl": "https://outlook.office.com/webhook/xxx" }
await notify.Teams.SendAsync(new NotificationPayload
{
    Subject = "Build Failed",
    Body    = "Pipeline `main` failed at step: Run Tests."
});

Telegram

"Telegram": { "BotToken": "123456:ABCdef...", "ChatId": "-1001234567890" }
await notify.Telegram.SendAsync(new NotificationPayload
{
    Body = "Server CPU usage above 90% for 5 minutes."
});

// Override ChatId per message via Metadata
await notify.Telegram.SendAsync(new NotificationPayload
{
    Body     = "DM to a specific user",
    Metadata = new() { ["chat_id"] = "987654321" }
});

Facebook Messenger

"Facebook": {
  "PageAccessToken": "EAAxxxxxxxxxxxxx"
}
await notify.Facebook.SendAsync(new NotificationPayload
{
    To   = "1234567890",  // recipient's page-scoped user ID (PSID)
    Body = "Your order has shipped! Track it here: yourapp.com/orders/123"
});

LINE

"Line": {
  "ChannelAccessToken": "xxxxxxxxxx",
  "ChannelSecret": "xxxxxxxxxx"
}
await notify.Line.SendAsync(new NotificationPayload
{
    To   = "U1234567890abcdef",  // LINE user ID
    Body = "Your appointment is confirmed for tomorrow at 10 AM."
});

Viber

"Viber": {
  "BotAuthToken": "xxxxxxxxxx",
  "SenderName": "Your App"
}
await notify.Viber.SendAsync(new NotificationPayload
{
    To   = "viber-user-id",
    Body = "Your verification code is 482910."
});

Mattermost

"Mattermost": {
  "WebhookUrl": "https://mattermost.yourapp.com/hooks/xxxxxxxxxx"
}
await notify.Mattermost.SendAsync(new NotificationPayload
{
    Subject = "Deploy Complete",
    Body    = "v2.4.1 deployed to production — all health checks passing."
});

Rocket.Chat

"RocketChat": {
  "WebhookUrl": "https://rocketchat.yourapp.com/hooks/xxxxxxxxxx"
}
await notify.RocketChat.SendAsync(new NotificationPayload
{
    Subject = "CI Pipeline",
    Body    = "Build #847 passed. Ready for QA review."
});

In-App

InApp has no config section — it is wired entirely in code. Register the handler before AddRecurPixelNotify:

// Program.cs — register your storage handler
builder.Services.AddInAppChannel(opts =>
    opts.UseHandler<IApplicationDbContext>(async (notification, db) =>
    {
        await db.AppNotifications.AddAsync(new AppNotification
        {
            UserId = notification.UserId,
            Title  = notification.Subject,
            Body   = notification.Body,
            IsRead = false
        });
        await db.SaveChangesAsync();
        return new NotifyResult { Success = true };
    }));

Send via orchestrator:

await notify.TriggerAsync("any.event", new NotifyContext
{
    User     = new NotifyUser { UserId = user.Id.ToString() },
    Channels = new() { ["inapp"] = new() { Subject = "New comment", Body = "Alex replied to your post." } }
});

Or direct:

await notify.InApp.SendAsync(new NotificationPayload
{
    To      = user.Id.ToString(),
    Subject = "New comment on your post",
    Body    = "Alex replied to your thread."
});

UseHandler IS the delivery — your code saves or pushes the notification. It is not the same as OnDelivery, which is a post-send audit callback.


Bulk send

Send to many recipients at once. Providers with native batch APIs use them automatically.

var payloads = users.Select(u => new NotificationPayload
{
    To      = u.DeviceToken,
    Subject = "Flash sale — 2 hours only",
    Body    = "Tap to shop now.",
    Metadata = new() { ["recipient_id"] = u.Id }
}).ToList();

var result = await notify.Push.SendBulkAsync(payloads);

if (!result.AllSucceeded)
{
    foreach (var failure in result.Failures)
        logger.LogWarning("Push failed for {Recipient}: {Error}", failure.Recipient, failure.Error);
}

Multi-channel event trigger

Fire email + SMS + push in parallel, with conditions and fallback. orchestratorOptions is the second parameter of AddRecurPixelNotify:

// Define once at startup
orchestratorOptions.DefineEvent("order.placed", e => e
    .UseChannels("email", "sms", "push")
    .WithCondition("sms",  ctx => ctx.User.PhoneVerified)
    .WithCondition("push", ctx => ctx.User.PushEnabled)
    .WithFallback("sms", "email")
    .WithRetry(maxAttempts: 3, delayMs: 500)
);

// Trigger from your service — all active channels fire in parallel
var result = await notify.TriggerAsync("order.placed", new NotifyContext
{
    User = new NotifyUser
    {
        Email         = order.CustomerEmail,
        Phone         = order.CustomerPhone,
        DeviceToken   = order.PushToken,
        PhoneVerified = order.Customer.PhoneVerified,
        PushEnabled   = order.Customer.PushEnabled,
    },
    Channels = new()
    {
        ["email"] = new() { Subject = "Order Confirmed #" + order.Id, Body = emailHtml },
        ["sms"]   = new() { Body = $"Order #{order.Id} confirmed. Track at yourapp.com/orders" },
        ["push"]  = new() { Subject = "Order Confirmed", Body = "Tap to view your order." }
    }
});