Channels
Beaco supports three delivery channels:
- SMS
- Webhook
Each channel has its own recipient requirements, runtime configuration, and retry policy.
Channel Overview
Channel choice is declared per recipient via channels.
Example:
{
"recipients": [
{
"channels": ["email", "sms"],
"email": "[email protected]",
"phone": "+15551234567"
}
]
}Beaco creates one notification per recipient-channel pair and routes each to the corresponding worker queue.
Email Channel
Email delivery is powered by Resend.
Recipient Requirements
For email channel, recipient must include:
email
Example recipient:
{
"channels": ["email"],
"email": "[email protected]"
}Content Model
Email supports:
- subject line
- body content (plain text and/or HTML depending on template usage)
Sender and Reply-To
By default every email is sent from the server's configured sender address. You can pick a different sender per template or per inline email:
from_localis the part before the@(for exampleorders). The domain always stays the server's verified domain, so a sender can never leave it.from_nameis the display name shown by mail clients.reply_tois any valid email address and needs no DNS setup.
{
"event_type": "order.confirmed",
"recipients": [{ "channels": ["email"], "email": "[email protected]" }],
"inline": {
"subject": "Order BEA-1042 confirmed",
"html": "<h1>Thanks for your order</h1>",
"from_local": "orders",
"from_name": "Winwell Orders",
"reply_to": "[email protected]"
}
}This sends as Winwell Orders <orders@your-verified-domain> with replies going to
[email protected]. When no field is set, the default sender is used. The same fields work
on templates; see Templates.
Attachments
Add attachments: [{ "filename": "invoice.pdf", "url": "https://files.example.com/a.pdf", "size_bytes": 48213 }] to an event to attach files to its emails (up to 10, 30 MB declared in
total). Beaco does not store the files: each url is downloaded at send time, by Resend or by
Beaco's worker when SMTP is the provider, so it must be publicly reachable and stay reachable
through retries.
Subject behavior:
- Uses template subject when available.
- Falls back to auto-generated subject when template subject is not defined.
Example Event (Email)
curl -X POST https://beaco.michaelogunjimi.com/api/v1/events \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_PROJECT_KEY" \
-d '{
"event_type": "password.reset",
"recipients": [{
"channels": ["email"],
"email": "[email protected]"
}],
"payload": {
"reset_url": "https://app.example.com/reset?token=abc"
}
}'SMS Channel
SMS delivery is powered by Twilio.
Recipient Requirements
For sms channel, recipient must include:
phonein E.164 format
Valid example:
+15551234567Invalid examples:
5551234567+1 (555) 123-4567
Content Model
SMS supports:
- plain text body only
SMS does not use a subject field.
Example Event (SMS)
curl -X POST https://beaco.michaelogunjimi.com/api/v1/events \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_PROJECT_KEY" \
-d '{
"event_type": "otp.sent",
"recipients": [{
"channels": ["sms"],
"phone": "+15551234567"
}],
"payload": {
"code": "093144"
}
}'Webhook Channel
Webhook delivery sends a JSON payload to your destination URL.
Recipient Requirements
For webhook channel, recipient must include:
webhook_url
Example:
{
"channels": ["webhook"],
"webhook_url": "https://example.com/beaco/hooks"
}Request Body Sent by Beaco
Webhook payload includes:
event_typepayloadnotification_idtimestamp
Example webhook body:
{
"event_type": "order.fulfilled",
"payload": {
"order_id": "ord_123"
},
"notification_id": "ntf_01j4za3vdy8r98t7b4s2v0x4bz",
"timestamp": "2026-01-12T11:02:17Z"
}URL Validation and SSRF Protection
Beaco validates webhook URLs before delivery:
- must use
httporhttps - hostname must resolve
- private/internal IP destinations are blocked
This reduces SSRF risk and prevents delivery to internal network targets.
Example Event (Webhook)
curl -X POST https://beaco.michaelogunjimi.com/api/v1/events \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_PROJECT_KEY" \
-d '{
"event_type": "invoice.paid",
"recipients": [{
"channels": ["webhook"],
"webhook_url": "https://example.com/hooks/invoices"
}],
"payload": {
"invoice_id": "inv_10022"
}
}'Channel Configuration
Each channel has configurable operational settings.
Common channel config fields:
| Field | Type | Description |
|---|---|---|
enabled | boolean | Enables or disables the channel |
rate_limit_per_minute | integer | Max outbound sends per minute for channel |
When a channel is disabled, Beaco skips new deliveries for that channel until re-enabled.
Rate limits help protect provider quotas and downstream systems.
Per-Channel Retry Policies
Retry behavior is configurable per channel.
Policy fields:
| Field | Description |
|---|---|
max_retries | Maximum retry attempts before dead-letter |
base_delay_seconds | Initial backoff delay |
max_backoff_seconds | Maximum delay cap |
jitter | Randomized delay offset to spread retries |
Example policy profile:
{
"email": {
"max_retries": 5,
"base_delay_seconds": 10,
"max_backoff_seconds": 600,
"jitter": true
},
"sms": {
"max_retries": 3,
"base_delay_seconds": 5,
"max_backoff_seconds": 120,
"jitter": true
},
"webhook": {
"max_retries": 8,
"base_delay_seconds": 15,
"max_backoff_seconds": 900,
"jitter": true
}
}Choosing the Right Channel
Use this quick heuristic:
| Scenario | Recommended Channel |
|---|---|
| User-facing transactional updates | |
| Time-sensitive short alerts | SMS |
| Service-to-service automation | Webhook |
You can combine channels for fallback or layered delivery.
Example strategy:
- primary: email
- urgent fallback: SMS
- internal automation: webhook
Validation Summary
| Channel | Required Recipient Field | Format Rules |
|---|---|---|
email | Valid email syntax | |
| SMS | phone | E.164 (+15551234567) |
| Webhook | webhook_url | Valid external http/https URL |
Operational Tips
Keep channel-specific provider credentials and limits environment-specific (dev/staging/prod).
Use low retry counts for SMS cost control, and higher retry windows for webhook recovery workflows.
Monitor per-channel failure rates to detect provider incidents quickly.
Related Docs
- Events for recipient schema and fan-out behavior.
- Templates for channel-specific content rendering.
- Delivery Pipeline for retries, DLQ, and suppression logic.
- Quickstart to send your first channel-specific event.

