Async Content Publishing: Why Your Agent Says 'Success' But Nothing Was Published
My agent told me ”✅ Publish successful.” The next morning, the article was nowhere to be found.
I checked the logs. HTTP 200. No errors. The API call looked perfect. But somehow, the content never made it to the platform.
This is the silent failure trap of async content publishing—and if you’re building agents that publish to blogs, CMS platforms, or social media, you’ve probably hit it too.
The Problem: HTTP 200 Doesn’t Mean “Published”
Here’s what happened in my case.
I had built an agent to publish articles to a content platform. The code was straightforward:
async function publishArticle(article) { const response = await fetch('/api/articles', { method: 'POST', body: JSON.stringify(article) });
if (response.ok) { return { success: true, message: '✅ Article published!' }; }
return { success: false, message: 'Failed to publish' };}The API returned HTTP 200. My agent reported success. I moved on to the next task.
The next day, I logged into the platform dashboard to check the article. Nothing. No article. No draft. No error message. Just… gone.
Digging Into the API Response
I decided to actually log the full API response instead of just checking response.ok:
async function publishArticle(article) { const response = await fetch('/api/articles', { method: 'POST', body: JSON.stringify(article) });
const data = await response.json(); console.log('Full response:', JSON.stringify(data, null, 2));
return { success: response.ok, data };}The output revealed the issue:
Full response: { "taskId": "task_abc123", "status": "pending", "audit_status": 2, "draft": true, "message": "Article submitted for review"}There it was: audit_status: 2 (pending review), draft: true, status: "pending".
The platform was using an async publishing pipeline. HTTP 200 just meant “I accepted your request into my queue.” The actual publishing happened later—after moderation, processing, or whatever the platform needed to do.
In my case, the article was rejected during moderation. But my agent had no way to know because I treated the initial HTTP 200 as “published.”
Why Platforms Do This
Content platforms rarely publish instantly. There are several reasons:
-
Moderation: Most platforms review content for policy violations, spam, or inappropriate material.
-
Processing: Images need resizing, videos need transcoding, markdown needs rendering.
-
Queues: High-volume platforms batch operations for efficiency.
-
Rate Limiting: Platforms may delay publishes to enforce rate limits.
This pattern is common across Medium, Dev.to, WordPress, social media APIs, and essentially any platform that handles user-generated content at scale.
The Fix: Poll for Status
I rewrote the agent to poll the status endpoint after submitting:
async function publishArticle(article) { // Step 1: Submit for publishing const response = await fetch('/api/articles', { method: 'POST', body: JSON.stringify(article) }); const { taskId, status } = await response.json();
// Step 2: Poll until terminal state const maxAttempts = 30; for (let i = 0; i < maxAttempts; i++) { await sleep(5000); // Wait 5 seconds between checks
const statusCheck = await fetch(`/api/tasks/${taskId}`); const result = await statusCheck.json();
if (result.status === 'published') { return { success: true, message: `Article published at ${result.url}`, url: result.url }; }
if (result.status === 'rejected') { return { success: false, message: `Article rejected: ${result.reason}`, reason: result.reason }; }
// Continue polling for 'pending', 'processing', 'in_review' }
return { success: false, message: 'Publishing timed out. Check platform dashboard.' };}
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms));}Now my agent waits until the content is actually live—or until it gets a definitive rejection—before reporting success or failure.
Alternative: Webhooks
Some platforms support webhooks instead of polling. This is cleaner if available:
async function publishWithCallback(article, callbackUrl) { const response = await fetch('/api/articles', { method: 'POST', body: JSON.stringify({ ...article, callback_url: callbackUrl }) });
return { success: 'pending', message: 'Article submitted. You will receive callback when published.', taskId: (await response.json()).taskId };}Then you need an endpoint to receive the callback:
app.post('/publish-callback', (req, res) => { const { taskId, status, url, reason } = req.body; notifyUser({ taskId, status, url, reason }); res.sendStatus(200);});Key Takeaways
After fixing this, I updated my mental model for any API that creates or publishes content:
-
Capture task/job IDs from the initial response—you’ll need them for verification.
-
Poll for status until you hit a terminal state (
published,rejected,failed). -
Report “submitted” not “published” until verification completes.
-
Handle timeouts—sometimes things get stuck in queues.
-
Surface rejection reasons—users need to know why content failed.
The most important change: I stopped trusting HTTP 200 as “success.” It’s just the beginning of the conversation, not the end.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments