Skip to content

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, or inline)
  • 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:

Text
POST /events

Full URL:

Text
https://beaco.michaelogunjimi.com/api/v1/events

Authentication:

Text
X-API-Key: <project API key>

Request Fields

FieldTypeRequiredDescription
event_typestringyesLogical event name, e.g. user.welcome
recipientsarrayyesOne or more recipient definitions
payloadobjectyesData for template rendering and downstream context
priorityenumnohigh, medium, low (default: medium)
template_idstringone of threeTemplate UUID for content rendering
template_namestringone of threeProject template name for content rendering
inlineobjectone of threeAlready-rendered {subject, html, text} email
attachmentsarraynoUp to 10 email files as {filename, url, size_bytes}
idempotency_keystringnoDuplicate-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

Bash
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:

JSON
{
  "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:

Bash
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:

JSON
{
  "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 channels array
  • channel-specific fields required by selected channels
  • optional user_id for your internal identity mapping

Recipient Shape

FieldTypeRequiredNotes
channelsarray<string>yesOne or more of email, sms, webhook
emailstringrequired for emailMust be valid email format
phonestringrequired for smsMust be E.164 format (+15551234567)
webhook_urlstringrequired for webhookMust be valid external http/https URL
user_idstringnoOptional app-level identifier

Example: Multi-Recipient, Multi-Channel

JSON
{
  "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:

StatusMeaning
acceptedEvent validated and persisted
processingNotifications are being created and/or delivered
completedAll notifications reached terminal success
partially_failedAt least one notification failed while others succeeded
failedEvent 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:

PriorityBehavior
highRouted for fastest processing
mediumDefault processing class
lowDeprioritized for non-urgent workloads

High priority events are processed first when queue pressure exists.

Use cases:

  • high: security alerts, password resets
  • medium: transactional user updates
  • low: 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 Accepted and creates event.
  • Duplicate submission with same key: returns 200 OK and original event.

Example: Idempotent Replay

Bash
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:

Text
POST /events/batch

Batch requests submit multiple events in one operation and are processed atomically.

If batch validation fails, no partial batch is committed.

Example: Batch Request

Bash
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:

Text
recipient × channel

Example:

  • 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

RuleExample
Valid email required for email channel[email protected]
E.164 phone required for sms channel+15551234567
Valid http/https URL required for webhook channelhttps://example.com/hook

SSRF Protection for Webhooks

Webhook URLs are validated to reduce SSRF risk:

  • URL must use http or https
  • hostname must resolve
  • private/internal IP ranges are rejected

Invalid targets are rejected at validation time.

Query an Event

Endpoint:

Text
GET /events/{id}

Example:

Bash
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

  1. Use stable, domain-driven event_type names (order.shipped, invoice.failed).
  2. Always send idempotency_key from upstream producers.
  3. Keep payloads explicit and template-focused.
  4. Use priority=high sparingly for truly urgent flows.
  5. Validate channel-specific data before calling Beaco.