Skip to content
Dashboard

Webhooks & Async Patterns

Handle asynchronous content generation with polling patterns and prepare for future webhook support.

Asynchronous Operations

Content generation (articles and social media) is asynchronous. When you start a generation, the API immediately returns a 202 response with an ID and a status of "generating". You then poll the status endpoint until the operation completes.

Article Generation Flow

Generating an article follows a simple three-step pattern:

1

Start Generation

POST /api/v1/articles/generate returns 202 with the article ID and status.

2

Poll Status

GET /api/v1/articles/:id/status until the status changes from "generating".

3

Retrieve Result

GET /api/v1/articles/:id for the full article content.

Status Transitions

StatusMeaningNext
generatingAI is working on the articledraft or failed
draftGeneration complete, ready for reviewpublished or scheduled
publishedArticle has been published
scheduledScheduled for future publicationpublished
failedGeneration encountered an error

Polling Article Status

The following examples show the complete generate-and-poll flow for articles:

# Start generation
curl -X POST https://brainpercent.app/api/v1/articles/generate \
  -H "Authorization: Bearer bp_your_key" \
  -H "Content-Type: application/json" \
  -d '{"topic": "AI Content Marketing", "length": "long"}'

# Poll status (repeat until status is not "generating")
curl https://brainpercent.app/api/v1/articles/ARTICLE_ID/status \
  -H "Authorization: Bearer bp_your_key"

Social Media Generation Flow

Social content generation follows a similar pattern but returns multiple items (one per platform). Each item has its own status that you poll independently.

202Social generation started
{
  "success": true,
  "data": {
    "batch_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
    "status": "generating",
    "items": [
      {
        "id": "s1a2b3c4-d5e6-7890-abcd-ef1234567890",
        "platform": "twitter",
        "status": "generating"
      },
      {
        "id": "s2a2b3c4-d5e6-7890-abcd-ef1234567890",
        "platform": "linkedin",
        "status": "generating"
      }
    ]
  },
  "meta": {
    "timestamp": "2026-02-01T00:00:00Z"
  }
}
async function generateSocialAndWait(apiKey, sourceUrl, platforms) {
  const genRes = await fetch('https://brainpercent.app/api/v1/social/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ source_url: sourceUrl, platforms }),
  });
  const { data: genData } = await genRes.json();

  // Poll each item until all are complete
  const results = [];
  for (const item of genData.items) {
    let content;
    while (true) {
      const res = await fetch(
        `https://brainpercent.app/api/v1/social/content/${item.id}`,
        { headers: { 'Authorization': `Bearer ${apiKey}` } }
      );
      content = (await res.json()).data;
      if (content.status !== 'generating') break;
      await new Promise(resolve => setTimeout(resolve, 3000));
    }
    results.push(content);
  }

  return results;
}

Use the following intervals and timeouts when polling for generation status:

OperationRecommended IntervalTypical DurationMax Wait
Article generation5 seconds30–60 seconds5 minutes
Social media generation3 seconds10–20 seconds2 minutes

Timeout Strategies

Always implement a timeout to avoid infinite polling loops. If the generation takes longer than the maximum expected duration, treat it as a failure and retry or alert the user.

async function pollWithTimeout(url, headers, timeoutMs = 300000) {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const res = await fetch(url, { headers });
    const { data } = await res.json();

    if (data.status !== 'generating') return data;

    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  throw new Error('Polling timed out');
}

Webhooks (Coming Soon)

Webhook support is on the roadmap. When available, you'll be able to register callback URLs to receive real-time notifications when article generation completes, social content is ready, or credits are running low. In the meantime, the polling pattern above is the recommended approach.