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:
Start Generation
POST /api/v1/articles/generate returns 202 with the article ID and status.
Poll Status
GET /api/v1/articles/:id/status until the status changes from "generating".
Retrieve Result
GET /api/v1/articles/:id for the full article content.
Status Transitions
| Status | Meaning | Next |
|---|---|---|
generating | AI is working on the article | draft or failed |
draft | Generation complete, ready for review | published or scheduled |
published | Article has been published | — |
scheduled | Scheduled for future publication | published |
failed | Generation 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.
{
"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;
}Recommended Poll Intervals
Use the following intervals and timeouts when polling for generation status:
| Operation | Recommended Interval | Typical Duration | Max Wait |
|---|---|---|---|
| Article generation | 5 seconds | 30–60 seconds | 5 minutes |
| Social media generation | 3 seconds | 10–20 seconds | 2 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.