Misar IO Docs
MisarMailApi Reference

Server-Sent Events (SSE)

Stream real-time AI generation and campaign send progress via Server-Sent Events.

Overview

MisarMail exposes two SSE endpoints for real-time streaming. Both use the standard text/event-stream format and work with the browser's native EventSource API or a manual fetch + ReadableStream pattern.


AI Email Generation Stream

POST api.misar.io/mail/ai/generate-email/stream
Authorization: Bearer msk_your_api_key
Content-Type: application/json

Streams AI-generated email content (subject line, body, or both) as Server-Sent Events.

Request body

{
  "type": "full",
  "prompt": "Write a re-engagement email for subscribers who haven't opened in 60 days",
  "tone": "friendly",
  "brandName": "Acme Corp"
}
type"subject" | "body" | "full"required

What to generate: just the subject line, just the body, or both.

promptstringrequired

Description of the email to generate.

tonestring

Writing tone. Examples: "professional", "friendly", "urgent".

brandNamestring

Your brand name to include in the generated copy.

Response headers

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

Event format

data: {"delta":"Here is your","type":"body"}

data: {"delta":" re-engagement email:","type":"body"}

data: {"done":true,"type":"body"}
deltastring

Incremental text chunk from the AI model.

type"subject" | "body" | "full"

Which part of the email this chunk belongs to.

doneboolean

true on the final event for each type. Followed by data: [DONE].

Browser example

const res = await fetch("https://api.misar.io/mail/ai/generate-email/stream", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer msk_your_api_key",
  },
  body: JSON.stringify({
    type: "full",
    prompt: "Re-engagement email for inactive subscribers",
    tone: "friendly",
  }),
});

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

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  for (const line of decoder.decode(value).split("\n\n")) {
    if (line === "data: [DONE]") return;
    if (line.startsWith("data: ")) {
      const event = JSON.parse(line.slice(6));
      if (event.delta) {
        output += event.delta;
        emailEditor.textContent = output;
      }
    }
  }
}

Campaign Send Progress Stream

GET api.misar.io/mail/campaigns/:id/send-stream
Authorization: Bearer msk_your_api_key

Streams real-time send progress for a campaign while it's being delivered.

Response events

data: {"status":"sending","sent":500,"total":10000,"bounced":12,"delivered":488,"opened":65}

data: {"status":"sent","sent":10000,"total":10000,"bounced":145,"delivered":9855,"opened":2340}

data: [DONE]
status"sending" | "sent" | "cancelled" | "failed"

Current campaign status. "sent", "cancelled", and "failed" are terminal.

sentnumber

Total emails sent so far.

totalnumber

Total recipients in the campaign.

bouncednumber

Emails that bounced (hard + soft).

deliverednumber

Confirmed deliveries.

openednumber

Tracked opens (pixel).

Stream behavior

  • Polls every 2 seconds
  • Terminal statuses close the stream immediately
  • Times out after 5 minutes and sends data: [DONE]
  • Returns {"error":"not_found"} if campaign ID doesn't belong to your account

Browser example

const campaignId = "your-campaign-uuid";

const res = await fetch(
  `https://api.misar.io/mail/campaigns/${campaignId}/send-stream`,
  { headers: { Authorization: "Bearer msk_your_api_key" } }
);

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

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  for (const line of decoder.decode(value).split("\n\n")) {
    if (line.startsWith("data: [DONE]")) return;
    if (line.startsWith("data: ")) {
      const ev = JSON.parse(line.slice(6));
      progressBar.style.width = `${(ev.sent / ev.total) * 100}%`;
      if (["sent", "cancelled", "failed"].includes(ev.status)) return;
    }
  }
}

Authentication

Both SSE endpoints require:

  • AI generation stream: API key (msk_) OR an authenticated session cookie
  • Campaign send stream: API key only (msk_)

The campaign must belong to the authenticated user's account. Attempting to stream another user's campaign returns 401.