Skip to content

Guides

Generations & streaming

Every article is produced by an asynchronous generation. Poll it, stream it live, or let a webhook tell you when it's done.

Lifecycle

POST /articles returns a generation in queued state. A worker picks it up within seconds, runs the pipeline and saves the article. Most articles finish in one to three minutes; pillar articles on premium models can take longer.

Generation statuses
statusMeaning
queuedWaiting for a worker. Can still be canceled (credits are refunded).
runningThe pipeline is working; see stage and progress.
succeededThe article is ready — fetch it via article_id.
failedSomething went wrong; error.code and error.message explain why. Credits were refunded.
canceledCanceled while queued. Credits were refunded.

While running, stage and progress (0–100) tell you where it is:

Stages
stageprogressWhat happens
queued0Waiting for a worker.
extracting5URL sources only: fetching and cleaning the source page.
outlining12Planning title, focus keyword and sections.
writing20–80Writing the introduction and sections (several in parallel); images are generated alongside.
optimizing80SEO pack: meta title and description, slug, excerpt, tags, FAQ.
finishing92Assembling, sanitizing and scoring the article.
done100Finished.

Polling

GET/api/v1/generations/{id}

The simplest integration: check every 5–10 seconds until the status is terminal. Polling counts toward your rate limit (120 requests per minute per key), so don't go below a couple of seconds.

curl https://reblogger.ai/api/v1/generations/$GENERATION_ID \
  -H "Authorization: Bearer $REBLOGGER_API_KEY"

Streaming events (SSE)

GET/api/v1/generations/{id}/events

For live UIs, open the text/event-stream. You receive the outline as soon as it's planned, then the article text as it's written. The stream replays all events from the beginning (or from Last-Event-ID), sends a comment ping every 15 seconds, and closes after done or error.

Event stream
retry: 2000

id: 812
event: stage
data: {"stage":"writing","progress":20}

id: 813
event: section_delta
data: {"section":-1,"text":"Growing vegetables on a balcony is easier than "}

id: 840
event: done
data: {"articleId":"cmh1x0art9q3m0001","title":"How to Start a Vegetable Garden on a Balcony","words":1532}

EventSource and headers

The browser's EventSource can't send an Authorization header, and API keys don't belong in the browser anyway. Consume the stream on your server with fetch (below) and relay what you need to your frontend.

const res = await fetch('https://reblogger.ai/api/v1/generations/' + generationId + '/events', {
  headers: { Authorization: `Bearer ${process.env.REBLOGGER_API_KEY}` },
});
const decoder = new TextDecoderStream();
let buffer = '';
for await (const chunk of res.body.pipeThrough(decoder)) {
  buffer += chunk;
  let end;
  while ((end = buffer.indexOf('\n\n')) >= 0) {
    const raw = buffer.slice(0, end);
    buffer = buffer.slice(end + 2);
    const event = /^event: (.+)$/m.exec(raw)?.[1];
    const data = /^data: (.+)$/m.exec(raw)?.[1];
    if (!event || !data) continue; // retry hints and pings
    const payload = JSON.parse(data);
    if (event === 'section_delta') process.stdout.write(payload.text);
    if (event === 'done') console.log('\nArticle ready:', payload.articleId);
    if (event === 'error') throw new Error(payload.message);
  }
}

Event reference

Event payloads mirror the live pipeline and use camelCase keys. Treat unknown event types as informational — we may add new ones.

SSE events
eventdataDescription
stage{ stage, progress }The pipeline moved to a new stage.
source{ title, url, words, via }URL sources: the extracted source page.
outline{ outline: { title, focusKeyword, sections: [{ heading, keyPoints, targetWords }] } }The planned structure.
section_delta{ section, text }A chunk of streamed Markdown for a section. Section -1 is the introduction.
section_done{ section, words }A section is complete.
image{ url, alt, width, height, section }An image is ready (section null = cover).
seo{ seo: { metaTitle, metaDescription, slug, tags, faq, … } }The SEO pack.
done{ articleId, title, words }Terminal: the article is saved. The stream closes.
error{ code, message }Terminal: the generation failed or was canceled. The stream closes.

Resuming

Every event has a numeric id. If the connection drops, reconnect with the header Last-Event-ID: 813 (or the query parameter ?last_event_id=813) to receive only newer events. Proxies that buffer responses can delay events — the stream already sends X-Accel-Buffering: no for nginx.

Canceling

POST/api/v1/generations/{id}/cancel

Generations that are still queued can be canceled and are refunded in full. Once a worker has started, the generation runs to completion (409 conflict). Deleting a queued article via DELETE /articles/{id} cancels it too.