Misar IO Docs
Misar.BlogStreaming

Newsletter Send Progress

Monitor newsletter issue send progress in real time using Server-Sent Events.

Overview

The newsletter send-stream endpoint delivers live progress updates while a newsletter issue is being sent to subscribers. Use it to display a real-time progress bar in your dashboard or integration.


Endpoint

GET api.misar.io/blog/newsletter/issues/:id/send-stream
Authorization: Bearer mbk_your_api_key

Returns text/event-stream — a Server-Sent Events stream.


Response headers

HeaderValue
Content-Typetext/event-stream
Cache-Controlno-cache, no-transform
X-Accel-Bufferingno

Event format

Each event is a JSON-encoded data line:

data: {"status":"sending","sent":250,"total":1000,"opened":42,"bounced":3}

data: {"status":"sent","sent":1000,"total":1000,"opened":380,"bounced":12}

data: [DONE]

Fields

status"sending" | "sent" | "failed" | "cancelled"

Current send status. "sent", "failed", and "cancelled" are terminal states.

sentnumber

Number of emails sent so far.

totalnumber

Total recipients in the issue.

openednumber

Emails opened (tracked via pixel).

bouncednumber

Emails that bounced.


Stream behavior

  • Polls the issue status every 3 seconds
  • Terminates automatically when status reaches "sent", "failed", or "cancelled"
  • Times out after 10 minutes and sends data: [DONE]
  • Returns error event {"error":"issue_not_found"} if the issue ID doesn't belong to your account

Error events

data: {"error":"issue_not_found"}
data: [DONE]
data: {"error":"poll_failed"}
data: [DONE]

Browser example

const issueId = "your-issue-uuid";
const token = "mbk_your_api_key";

const source = new EventSource(
  `https://api.misar.io/blog/newsletter/issues/${issueId}/send-stream`,
  {
    // EventSource doesn't support Authorization headers — use a short-lived
    // signed URL or proxy the request through your backend
  }
);

// Alternatively use fetch + ReadableStream for header support:
const res = await fetch(
  `https://api.misar.io/blog/newsletter/issues/${issueId}/send-stream`,
  { headers: { Authorization: `Bearer ${token}` } }
);

const reader = res.body!.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const lines = decoder.decode(value).split("\n\n");
  for (const line of lines) {
    if (line.startsWith("data: [DONE]")) return;
    if (line.startsWith("data: ")) {
      const event = JSON.parse(line.slice(6));
      updateProgressBar(event.sent, event.total);
      if (["sent", "failed", "cancelled"].includes(event.status)) return;
    }
  }
}

Authentication

Requires an API key with at least read scope. The issue must belong to the authenticated user's account.