Skip to main content

Overview

Bulletin provides personalized digest notifications via email and Telegram. Users receive summaries of new stories from profiles they follow.

Digest Frequencies

  • daily - Every day at preferred time
  • bidaily - Every 2 days at preferred time
  • weekly - Once per week at preferred time

Delivery Channels

Email

HTML email digest with story summaries

Telegram

Telegram bot message with formatted digest

Get Bulletin Preferences

GET /{locale}/bulletin/preferences
Authentication Required
Get unified bulletin preferences for the settings UI.
curl "http://localhost:8080/en/bulletin/preferences" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
{
  "data": {
    "frequency": "daily",
    "preferred_time": 9,
    "channels": ["email", "telegram"],
    "email": "[email protected]",
    "telegram_connected": true,
    "last_bulletin_at": "2024-03-07T09:00:00Z"
  }
}
frequency
string
Digest frequency: daily, bidaily, weekly
preferred_time
integer
Preferred delivery hour (0-23 UTC)
channels
array
Active delivery channels: email, telegram
email
string
User’s email address (from account)
telegram_connected
boolean
Whether Telegram is connected
last_bulletin_at
string
Last bulletin delivery timestamp (ISO 8601)

Update Bulletin Preferences

PUT /{locale}/bulletin/preferences
Authentication Required
Atomically update all bulletin preferences. This endpoint manages subscriptions for all channels.
frequency
string
required
Digest frequency: daily, bidaily, weekly
preferred_time
integer
required
Preferred delivery hour (0-23 UTC)
channels
array
required
Active channels: ["email"], ["telegram"], or ["email", "telegram"]
curl -X PUT "http://localhost:8080/en/bulletin/preferences" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "frequency": "daily",
    "preferred_time": 9,
    "channels": ["email", "telegram"]
  }'
Response:
{
  "data": {
    "updated": true
  }
}
Atomic UpdatesThis endpoint creates/updates/deletes subscriptions as needed to match the desired state. Passing an empty channels array unsubscribes from all channels.

List Subscriptions

GET /{locale}/bulletin/subscriptions
Authentication Required
List individual channel subscriptions (low-level API).
curl "http://localhost:8080/en/bulletin/subscriptions" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
{
  "data": [
    {
      "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
      "profile_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
      "channel": "email",
      "frequency": "daily",
      "preferred_time": 9,
      "last_bulletin_at": "2024-03-07T09:00:00Z",
      "created_at": "2024-01-15T10:30:00Z"
    },
    {
      "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
      "profile_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
      "channel": "telegram",
      "frequency": "daily",
      "preferred_time": 9,
      "last_bulletin_at": "2024-03-07T09:00:00Z",
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}

Subscribe to Bulletin

POST /{locale}/bulletin/subscribe
Authentication Required
Create a new channel subscription (low-level API). Consider using PUT /bulletin/preferences instead.
channel
string
required
Channel: email or telegram
frequency
string
default:"daily"
Digest frequency: daily, bidaily, weekly
preferred_time
integer
required
Preferred delivery hour (0-23 UTC)
curl -X POST "http://localhost:8080/en/bulletin/subscribe" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "frequency": "daily",
    "preferred_time": 9
  }'

Update Subscription

PUT /{locale}/bulletin/subscriptions/{id}
Authentication Required
Update subscription preferences (low-level API).
id
string
required
Subscription ID
frequency
string
required
New frequency: daily, bidaily, weekly
preferred_time
integer
required
New preferred hour (0-23 UTC)

Unsubscribe

DELETE /{locale}/bulletin/subscriptions/{id}
Authentication Required
Delete a channel subscription (low-level API).
id
string
required
Subscription ID
curl -X DELETE "http://localhost:8080/en/bulletin/subscriptions/01ARZ3NDEKTSV4RRFFQ69G5FAV" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Admin Endpoints

Trigger Bulletin Processing

POST /admin/bulletin/trigger
Admin Authentication Required
Manually trigger bulletin digest processing for all due subscriptions.
curl -X POST "http://localhost:8080/admin/bulletin/trigger" \
  -H "Authorization: Bearer ADMIN_JWT_TOKEN"
Response:
{
  "data": {
    "triggered": true
  }
}
This endpoint is typically called by a cron job every hour. It processes all subscriptions that are due based on frequency and preferred time.

Bulletin Digest Content

Digests contain:
  • Stories published since last bulletin
  • Grouped by followed profile (author)
  • Includes AI-generated summary (if available)
  • Profile picture and links
  • Call-to-action buttons
Email Format:
  • HTML email with responsive design
  • Story cards with images
  • “Read More” buttons linking to stories
Telegram Format:
  • Formatted text with Markdown
  • Story summaries
  • Inline links to full stories

Requirements

Email Channel

  • Requires valid email address in user account
  • Uses user’s default locale for content
  • Sends from [email protected]

Telegram Channel

  • Requires Telegram bot connection (see Telegram API)
  • User must have started conversation with bot
  • Uses Telegram chat ID from profile link
Telegram SetupTo receive Telegram bulletins:
  1. Connect your Telegram account via profile links
  2. Start a conversation with the Aya bot
  3. Subscribe to bulletin with telegram channel

Preferred Time (UTC)

All times are in UTC (0-23). Users should convert from their local timezone:
// Convert local time to UTC
const localHour = 9; // 9 AM local time
const timezoneOffset = new Date().getTimezoneOffset() / 60;
const utcHour = (localHour + timezoneOffset + 24) % 24;

console.log(`9 AM local = ${utcHour} UTC`);

Error Handling

{
  "data": null,
  "error": {
    "message": "No individual profile found",
    "code": 400
  }
}

Build docs developers (and LLMs) love