Events
Events are the primary trigger mechanism in Beaco.
You publish an event that describes what happened, and Beaco handles notification fan-out, queueing, delivery, and tracking.
What Is an Event?
An event is a structured request that includes:
- what happened (
event_type) - who should be notified (
recipients) - context data (
payload) - one content source (
template_id,template_name, orinline) - optional delivery controls (
priority,idempotency_key)
Beaco stores the event and creates notification records asynchronously.
Exactly one of template_id, template_name, or inline is required. Inline content bypasses
Jinja rendering completely; strings such as {{ untouched }} are sent literally.
Create an Event
Endpoint:
POST /eventsFull URL:
https://beaco.michaelogunjimi.com/api/v1/eventsAuthentication:
X-API-Key: <project API key>Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | yes | Logical event name, e.g. user.welcome |
recipients | array | yes | One or more recipient definitions |
payload | object | yes | Data for template rendering and downstream context |
priority | enum | no | high, medium, low (default: medium) |
template_id | string | one of three | Template UUID for content rendering |
template_name | string | one of three | Project template name for content rendering |
inline | object | one of three | Already-rendered {subject, html, text} email |
attachments | array | no | Up to 10 email files as {filename, url, size_bytes} |
idempotency_key | string | no | Duplicate-prevention key for safe retries |
Attachments are referenced by URL and never stored by Beaco: each url is downloaded when
sending, so it must be publicly reachable and stay reachable until delivery succeeds. The declared size_bytes of all
files may total at most 30 MB. See the API reference for the full contract.
Example: Single Event
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",
"priority": "high",
"template_id": "tmpl_invoice_paid",
"idempotency_key": "evt-invoice-78341-v1",
"recipients": [{
"channels": ["email", "sms"],
"email": "[email protected]",
"phone": "+15551234567",
"user_id": "usr_123"
}],
"payload": {
"invoice_id": "inv_78341",
"amount": "49.00",
"currency": "USD"
}
}'Typical response for first submission:
{
"id": "evt_01j4z89n8x5t5b5w3j9m8k0h2z",
"status": "accepted",
"event_type": "invoice.paid"
}End-to-End Branded Order Confirmation
After syncing the order-confirmed template from the Templates guide, send by name:
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": "order.confirmed",
"template_name": "order-confirmed",
"idempotency_key": "order-BEA-1042-confirmed",
"recipients": [{"channels":["email"],"email":"[email protected]"}],
"payload": {"customer_name":"Chidi","order_number":"BEA-1042"}
}'If your app already rendered the email, send it without first creating a template:
{
"event_type": "order.confirmed",
"recipients": [{ "channels": ["email"], "email": "[email protected]" }],
"inline": {
"subject": "Order BEA-1042 confirmed",
"html": "<main><h1>Thanks, Chidi</h1><p>Your order is confirmed.</p></main>",
"text": "Thanks, Chidi. Your order is confirmed."
},
"payload": {},
"idempotency_key": "order-BEA-1042-confirmed"
}Recipients
Each recipient object defines:
- a
channelsarray - channel-specific fields required by selected channels
- optional
user_idfor your internal identity mapping
Recipient Shape
| Field | Type | Required | Notes |
|---|---|---|---|
channels | array<string> | yes | One or more of email, sms, webhook |
email | string | required for email | Must be valid email format |
phone | string | required for sms | Must be E.164 format (+15551234567) |
webhook_url | string | required for webhook | Must be valid external http/https URL |
user_id | string | no | Optional app-level identifier |
Example: Multi-Recipient, Multi-Channel
{
"event_type": "order.shipped",
"template_name": "order-shipped",
"recipients": [
{
"channels": ["email"],
"email": "[email protected]",
"user_id": "usr_alice"
},
{
"channels": ["sms", "webhook"],
"phone": "+15551234567",
"webhook_url": "https://example.com/hooks/order-events",
"user_id": "usr_ops"
}
],
"payload": {
"order_id": "ord_10019"
}
}Event Lifecycle
Events move through explicit statuses:
| Status | Meaning |
|---|---|
accepted | Event validated and persisted |
processing | Notifications are being created and/or delivered |
completed | All notifications reached terminal success |
partially_failed | At least one notification failed while others succeeded |
failed | Event could not be processed to successful completion |
Event status is aggregate state. Individual notifications have their own delivery statuses.
Priority Levels
Set priority to influence queue routing:
| Priority | Behavior |
|---|---|
high | Routed for fastest processing |
medium | Default processing class |
low | Deprioritized for non-urgent workloads |
High priority events are processed first when queue pressure exists.
Use cases:
high: security alerts, password resetsmedium: transactional user updateslow: bulk informational events
Idempotency
Idempotency prevents duplicate event creation on client retries.
Include the same idempotency_key when retrying a request after a timeout or network error.
Behavior:
- First submission: returns
202 Acceptedand creates event. - Duplicate submission with same key: returns
200 OKand original event.
Example: Idempotent Replay
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": "user.welcome",
"template_name": "welcome-email",
"idempotency_key": "welcome-user-abc-001",
"recipients": [{"channels":["email"],"email":"[email protected]"}],
"payload": {"user_name":"Alice"}
}'Repeat the exact call with the same idempotency_key to get the previously created event response.
Batch Events
For multi-event ingestion, use:
POST /events/batchBatch requests submit multiple events in one operation and are processed atomically.
If batch validation fails, no partial batch is committed.
Example: Batch Request
curl -X POST https://beaco.michaelogunjimi.com/api/v1/events/batch \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_PROJECT_KEY" \
-d '{
"events": [
{
"event_type": "user.welcome",
"template_name": "welcome-email",
"recipients": [{"channels":["email"],"email":"[email protected]"}],
"payload": {"user_name":"A"}
},
{
"event_type": "user.welcome",
"template_name": "welcome-email",
"recipients": [{"channels":["email"],"email":"[email protected]"}],
"payload": {"user_name":"B"}
}
]
}'Event → Notification Fan-Out
Beaco creates one notification per:
recipient × channelExample:
- 2 recipients
- channels per recipient:
["email","sms"]
Result:
- 4 notifications total
This fan-out model ensures channel isolation and independent retry behavior.
Validation Rules
Beaco validates event payloads before acceptance.
Recipient and Channel Validation
| Rule | Example |
|---|---|
Valid email required for email channel | [email protected] |
E.164 phone required for sms channel | +15551234567 |
Valid http/https URL required for webhook channel | https://example.com/hook |
SSRF Protection for Webhooks
Webhook URLs are validated to reduce SSRF risk:
- URL must use
httporhttps - hostname must resolve
- private/internal IP ranges are rejected
Invalid targets are rejected at validation time.
Query an Event
Endpoint:
GET /events/{id}Example:
curl -X GET https://beaco.michaelogunjimi.com/api/v1/events/evt_01j4z89n8x5t5b5w3j9m8k0h2z \
-H "X-API-Key: YOUR_PROJECT_KEY"Use this endpoint to track event-level progress.
For delivery-level detail, use Delivery Pipeline and notification endpoints.
Best Practices
- Use stable, domain-driven
event_typenames (order.shipped,invoice.failed). - Always send
idempotency_keyfrom upstream producers. - Keep payloads explicit and template-focused.
- Use
priority=highsparingly for truly urgent flows. - Validate channel-specific data before calling Beaco.

