
PostSider
Social media scheduling and publishing tool
Two posts ago I wrote that the version of my feature that survived contact with my own drafts was the boring one, and that I had learned to trust it. This is what the boring version has been shipping since. None of it makes a screenshot. All of it is why I would now let an agent near a publish button.
A key that makes retries not create duplicates
PostSider's create-post endpoint now accepts an Idempotency-Key header. Send the same key on a retry and the API returns the original result instead of creating a second post. Replay the key with a different body and it answers 409 Conflict.
This is the fix for the failure I documented in my dogfooding post: X answered my media upload with "Unknown Error". Any sane pipeline retries that. Without a stable key, a retry after an ambiguous error is exactly how the same caption goes out twice, seconds apart, on an account a client is watching. With the key, the retry becomes a lookup. There is no screenshot of a duplicate post that did not happen.
Webhooks you can actually trust
The post.published webhook now ships signed: an HMAC-SHA256 signature over the timestamp and raw body, plus an attempt counter. The SDK has a one-call verifier. Reject anything older than five minutes, fail closed on a bad signature, dedupe on the post id.
Your own dashboard counting a publish twice is also a bug, and one you cannot see in the product. A signed event with a dedup key turns "probably went live" into "went live, recorded once".
An MCP surface that stops being just a publish button
The MCP server quietly grew past create-post. Agents can now list channels, read the queue, check a post for missing fields, request approval, read approval status, pull per-post and channel analytics, upload media from a URL, even pause publishing. A publish tool is a gun. A surface with approvals, statuses and a pause switch is a control room.
Why this matters more than the visible stuff
Everything here is invisible by design. No demo video ends with "and here the idempotency key returns the original result". But this is the line between an agent that can post and an agent I would let post on an account that pays my rent. The glamorous version gets the launch post. The boring version keeps the account.
What feature did you ship that earned zero screenshots but kept you alive? And what would you still require before you let an agent publish without approval?
On June 27 I posted here about a virality-estimator feature I'd seen on Higgsfield and announced I was building the same thing for PostSider, my social publishing tool.
Three days later, the first version of the feature existed. It is not what I promised, and I think that's the interesting part.
What I actually built — a Post Checker:
You paste a draft, it returns a score from 0–100.
But not one number: four dimensions — hook, clarity, CTA, platform fit — plus a list of specific positives and negatives.
It knows which platform the post targets. An X post and a LinkedIn post get judged differently, because a great one is usually a bad version of the other.
It knows if the post has media, and it can carry your brand context.
A caption rewrite with a tone setting rides along.
Why it drifted from "virality": a single "92/100 virality" number is a black box. I couldn't defend it, and users can't act on it. But "your hook is buried in the third sentence" is actionable. Also, platform fit kept beating raw virality in everything I tested — the highest-scoring draft is the one that should never have been published on that platform.
Practical detail I'm unreasonably proud of: it runs on DeepSeek or Gemini or OpenAI with your own key, so a check costs a fraction of a cent. Cheap enough that the tool isn't a ceremony you save for big posts — it's the gate every draft walks through. Which fits the lesson from my last post here: the hard part of publishing isn't connecting platforms, it's knowing when not to publish. The checker is that lesson productized: it's a "do not publish this yet" gate with receipts, not a crystal ball.
The honest bit: I announced the glamorous version, and the version that survived contact with my own drafts is the boring one that stops me from embarrassing myself. I've learned to trust the boring version.
Do you score your drafts before publishing? And what would you rather have — a virality number, or a list of what's wrong with the post?
1 Like
Comment
I am building PostSider, a social publishing tool for teams and AI agents.
At first, I measured progress by the number of platforms I could connect.
One more provider working. One more OAuth flow approved. One more API request returning a successful response.
That felt like progress.
Then I realized that every new platform adds another way to publish the wrong thing at the wrong time.
The difficult question is not:
Can the agent send a publish request?
The difficult question is:
Should this post be published at all?
An AI agent is very good at producing a valid request.
It can write the caption, attach the media, select a channel, choose a time and call the API.None of those actions prove that the post should go live.The account might be wrong.The approval might be missing.The offer might have expired.The media might not be ready on the platform.The token might have expired.The post might already have been published by another workflow.The content might be technically valid and still be a terrible idea.That changed how I think about automation.
The default path should not be:
agent writes → platform publishes
It should be:
agent drafts → checks the post → human reviews → queue schedules → platform publishes
The agent can do most of the mechanical work.
It can prepare platform-specific variants. It can check whether required fields are missing. It can find the next available slot. It can put the post into the right workspace.
But there needs to be a point where the system can say:
Not yet.
That is not a failure of automation.
That is the part that makes automation usable.
I now think there are several good reasons not to publish:
The destination channel is ambiguous.
The post has not passed the required review.
The media is not confirmed as ready.
The offer, price or availability may have changed.
The agent cannot explain why this post is being published now.
The request looks like a duplicate.
The platform returned an unclear result.
The post is outside the campaign's approved timing.
A green API response is not the same thing as a good publishing decision.
This is especially important when one workflow touches many platforms. Each platform has slightly different rules, permissions, media behavior and failure modes.
The more platforms you connect, the less useful “it worked in testing” becomes.
A system that works on one network can still make a bad decision across thirty others.The product lesson for me is that the queue is not just a place where posts wait.
It is a control surface.
A draft should be visible before it becomes a scheduled post.A scheduled post should be easy to inspect.A failed post should remain visible instead of disappearing into a log.
A human should be able to stop or change something without fighting the automation that created it.I am not trying to make an agent autonomous as quickly as possible.
I am trying to make its actions understandable enough that autonomy becomes a choice instead of a risk.
Thirty platforms is an integration problem.Knowing when not to publish is a product problem.What would you require before allowing an AI agent to publish without approval?A sandbox? A rollback button? A confidence score? Or would you never give it that permission?
Łukasz Blania
2 Likes
9 Comments
9 Comments
-
1This matches what I learned while building a WordPress publishing pipeline. The safest design was to separate Generated, Scheduled, and Published into durable states instead of treating a successful API call as the finish line. Each article also needs one reserved publication slot, idempotent checks, visible warnings, and a watchdog that can recover a missed cron event without publishing twice. I ended up offering three modes: draft-only, pending human review, and quality-gated automatic publishing. The important part is that switching to a safer mode removes future schedules without deleting the generated work or its history. For me, the minimum before unattended publishing is: explicit destination, validated content and media, a unique slot reservation, an expiry check for time-sensitive claims, and a recoverable audit trail. I’d treat a rollback button as useful, but prevention and idempotency matter more because some external side effects cannot truly be rolled back. How are you modelling the difference between a recoverable “not ready yet” state and a permanent blocker?
-
1Thanks! The "API call as the finish line" trap is exactly what I keep running into. I split it by who can unblock it. "Not ready yet" = something specific is missing (approval, media, a slot) — the post is fine, it just waits. It stays visible in the queue with the reason, someone resolves it, it picks up where it stopped. A permanent blocker = the post itself is no longer valid. Offer expired, account dead, content superseded. Retrying won't help, so it surfaces as an exception and a human decides: reschedule, edit or kill it. Main rule: the system should never quietly retry its way from blocked to published.
-
-
1The inspect-and-delete layer feels more important than the memory itself. Curious whether users actually engage with the Memory Book to correct or remove things, or whether simply knowing they can see and control the memory is what makes the companion feel trustworthy.
-
1Good point. I think you're right that the memory itself isn't the valuable part — it's that the user knows they can see it and remove it. For me the inspect layer is the whole point: drafts visible before they go live, failed posts don't disappear into logs, and you can always stop or change something without fighting the tool. Whether people actually use the edit/remove often — my guess is the *knowing it's there* matters more. Control you rarely use still builds trust.
-
1That makes sense. The more interesting test will be whether that sense of control actually reduces hesitation to let the system act, even when users rarely need to exercise it.
-
1Exactly — that's the real question I want to see answered in practice. If giving people a visible escape hatch actually makes them more willing to let the system act, that's the whole game. I'm dogfooding it myself — my agents schedule my own posts through this flow, so I'm both the builder and the most anxious user. Curious how many people will confirm the same pattern once they try it.
-
1That’s a much stronger test than just asking users whether they like the idea. I’d be curious whether the escape hatch actually changes behavior — specifically, whether people let the system act more often once they know they can inspect and undo it.
-
1
Yeah, it would definitely be worth measuring. The tricky part is privacy — I don’t want to track too much of what users or their agents are actually doing.
One thing I added specifically for this is an approval flow. An agent can send a post for approval instead of publishing it directly, and the user can review, edit, approve, or reject it.
I think that’ll probably be the most common middle ground between manual and fully autonomous publishing. In real use, Vincent is already doing something similar — planning content for the whole month, then reviewing the plan, removing what doesn’t make sense and approving the rest.
So I’m really curious whether people naturally move from approval-first to giving the agent more autonomy over time.
-
1That approval-first to autonomy transition is the part I’d be most interested in understanding further. It’s a much more consequential signal than whether users simply like the control layer. Happy to continue that privately — what’s the best email to reach you on?
-
-
-
-
-
-
I run Local Waifu's social calendars (X, Instagram, TikTok, Facebook, YouTube, roughly 40 scheduled posts a week) through PostSider, the social publishing tool I built. The scheduler is my own code. The queue is my own code. The errors that came back this week were also, in a very real sense, my own code.
This week, my product broke five times in five different ways. None of them took the platform down. All of them were visible in the post queue, which is the part I care about: when you schedule through your own product, the failure state is a row in a calendar, not a ticket in someone else's inbox.
Failure 1: TikTok said my app is not allowed to post publicly. The API returned "unaudited_client_can_only_post_to_private_accounts." Ten scheduled posts died on arrival. This one is not a bug in my code: the TikTok app needs a human audit before it can publish to public accounts, and the audit has not happened yet. The scheduler did its job. The platform said no.
Failure 2: Facebook rejected every video with a permission error. "No permission to publish the video," error 100. I assumed it was a Meta access-level issue for weeks. It was not. The fix turned out to be a missing scope in my own provider code: the Facebook integration never requested pages_video_upload, so the publish call was doomed from the start, for every user, on day one. My own video posts were the ones that made me read the provider file.
Failure 3: X returned "Unknown Error" while uploading media. Not a helpful message. The post stayed in the queue marked failed. No crash, no alert, just a row that did not go live.
Failure 4: Instagram said "media not ready" and "media fetch failed." Two different posts, two different media, same morning. The containers did not finalize. Nothing in my code changed between the posts that worked and the ones that did not.
Failure 5: YouTube stopped refreshing its token. "Could not refresh your youtube channel. Please go back to the system and connect it again." A scheduled video simply stopped having a channel to go to.
That is the whole list. Twelve posts published fine that same week, five failed, and every failure was a different flavor. If I had been running this marketing through a tool built by someone else, I would have filed a support ticket and waited. Because it is my product, I read the provider source, found the missing scope, and scheduled the fix.
The lesson I keep re-learning: dogfooding is not a marketing trick, it is a QA loop with a face. A bug you hit while doing your own work comes with context: which platform, which media type, which settings, what you were trying to do at 7am. A bug report from a user arrives with none of that. Using your own product for your own marketing is the cheapest way to make your own bugs explain themselves.
The second lesson is about failure states. My product stores every failed post as a row in a calendar, with the platform's error message attached. That single decision turned five silent disasters into five visible rows. The platform error text is ugly, and that is exactly why it is useful: the queue shows me the truth, not a green checkmark.
The third lesson is about ordering. The TikTok rejection is not mine to fix, the YouTube token is a reconnect click, the X and Instagram media failures are still being diagnosed, and the Facebook scope is already patched in the codebase. Dogfooding told me which ones were mine.
I shipped a scheduling tool so my own calendars would stop being manual work. What I did not expect: my own calendars would become the test suite. If you build something you can use, use it. Your product will tell you the truth faster than any user ever will.
I build PostSider, a publishing tool aimed at agencies and at AI agent workflows, meaning the step at the end of an automated content pipeline where something actually goes live.
The scheduler was the easy half. Getting the platforms to let my app touch their APIs took 6 weeks with Meta, 5 with TikTok, and 6 rejections between them. Here is what actually got me rejected, because I could not find this written down anywhere when I started.
TikTok: my Website URL was a login screen
I submitted app.postsider.com, which is the authenticated app. It renders client side, so a reviewer opening it sees a loading state and then a login form. The rejection note said the external website must be fully developed and cannot be a landing or login page.
The fix took ten minutes and cost me two weeks of calendar time: submit the marketing domain, postsider.com, not the app subdomain. Redirect URI stays pointed at the app. If you genuinely have to submit something behind a login, put test credentials in the Apply Reason field, because they will not go looking for them.
One more thing that is easy to miss: the domain in your demo video has to match the Website URL you submitted. If the video opens on the app subdomain and the field says something else, that is another round.
LinkedIn: the request button was greyed out and nobody says why
I wanted Community Management API for posting to company pages. The Request Access button was simply disabled, with no explanation anywhere in the portal.
The reason is that Community Management has to be the only product on the application. My app already had Share on LinkedIn and Sign In with LinkedIn using OpenID Connect attached, and that combination silently kills the button. The answer is a second, clean LinkedIn app with nothing else on it. That single product then gives you both w_member_social and w_organization_social, so you are not losing anything.
I lost days assuming it was an account standing issue.
Meta: verification first, then one screencast per permission
Business verification comes before app review and it is about your company, not your product. I run a sole proprietorship in Poland, and anything that did not match my registered details exactly bounced back.
Then App Review, per permission, each with a screencast where a reviewer watches that specific permission being used from login to result. They are not exploring your product. They are checking one box, and if the video does not show that box, the rest of the video does not matter.
What I would tell past me
Start the reviews on day one, before the product is finished. The review is the long pole, not the code. I built first and applied second and that ordering is where most of the eleven weeks went.
Read every field description in each portal, slowly. My most expensive rejection came from putting a correct URL in the wrong field.
I also kept a plan B the whole time, which is why I could keep working instead of quietly abandoning it. PostSider is AGPL-3.0, so anyone can self host it with their own developer credentials. If a platform had decided my hosted product was a problem, the code would still exist and the users with their own API access would still have a tool. Smaller business than the SaaS, and worse than plan A, but it turns a rejection into a bad quarter rather than an extinction event.
Anyone else here shipped something gated behind platform review? I am curious whether resubmitting reset your position in the queue or held it, because I could never tell.
2 Likes
1 Comment
1 Comment
-
1
The interesting part is that once you have enough data, the problem can actually become harder rather than easier.
There are usually plenty of things you could work on next. The harder question seems to be which signal is strong enough to justify choosing one over the others.
Curious how you're thinking about that distinction in Powsight.
After a 10 day outage that never triggered a single alert, I went through my own social media scheduling app looking for every other place it could fail without telling anyone. I found 36 of them.
PostSider schedules and publishes posts across a dozen platforms. The outage that started this was a startup race: the worker process that actually publishes posts failed to connect on boot, so it silently did nothing, while the health check only tested "is the web server up," which it was. Posts queued for ten days. Nobody got an error. I only found it because a user finally asked why nothing had gone out.
Fixing that one bug felt like closing a hole in a boat, so I went looking for the rest of the boat.
The pattern I hunted for was specific: any place where the code caught a failure and returned success anyway, or where a loop could run forever without ever reporting that something was stuck. Not crashes. Crashes are loud. I wanted the quiet ones.
Eight platform integrations had the exact same shape of bug: a publish attempt would fail on the platform's side, and the integration would catch that, log nothing useful, and tell the rest of the app it worked. Slack, Notion, Medium, X, and four others. From the user's point of view, the post just never appeared, with zero indication why, weeks after the fact if they even noticed.
One of the more specific finds: the Mastodon integration for custom instances was posting to mastodon.social instead of the instance the user actually configured. Anyone who runs their own instance, which is most serious Mastodon users, had every post going to the wrong place while the app reported success on all of them.
A separate integration was leaking a refresh token into the request meant for a completely different platform, a copy paste bug in code that handles two providers close together in the file.
Eight more integrations had status polling loops with no upper bound. If a platform's API stopped responding the way the code expected, the loop just kept polling forever instead of giving up and surfacing an error.
None of these were exotic bugs. Every one of them was a try/catch that swallowed the failure case, or a while loop with no exit condition for the unhappy path. The kind of thing that passes every test you write, because you write tests for the happy path.
What I'd tell another founder shipping integrations against platforms you don't control: go through every single external call in your codebase and ask one question. If this call fails in a way I have not anticipated, does my code find out, or does it assume success and move on. That question alone found all 36.
132 tests green after the fixes, and the health check now actually checks whether the background workers are running, not just whether the process is alive.
PostSider is what I've been building since. If the failure-hunting method is useful on your own stack, happy to compare notes, and the app itself is at postsider.com.
What's the sneakiest silent failure you've found in your own codebase, the kind that passed every test and still shipped?
2 Likes
Comment
PostSider is done. The backend works, the scheduler works, the OAuth flows work. I cannot launch it.
I am waiting on API review from Meta and TikTok. Until a reviewer at each company clicks approve, my product technically exists and practically does not. That is the whole post. I want to talk about what that feels like when you are solo and what I am actually doing with the wait.
What I underestimated
I thought platform risk meant "they might ban me later." It does not. It starts before you have a single user.
Every social platform gates its publishing API behind a review process, and the review is not about your code. It is about your paperwork. Privacy policy live at a real URL. Terms of service. A demo video showing exactly the permission scopes you asked for. Business verification. A use case description that matches, word for word, what your app actually does.
TikTok rejected me once. The reason was the Website URL field in the developer portal. Not the scopes, not the use case, not the video. One wrong field, back of the queue.
LinkedIn is worse in a different way. The Community Management API needs its own application, separate from whatever you already have approved. So the work I did for LinkedIn access does not carry over. Fresh app, fresh review.
That is three separate bureaucracies, each with its own timeline, and my launch is the intersection of all three.
The part nobody warns you about
When you are solo, waiting is not neutral. It is expensive.
I work a full time night shift job that has nothing to do with software. My build time is the hours around it. Every week PostSider sits in review is a week I spent building something I cannot sell, while my energy budget stays exactly the same size.
There is also a motivation tax. Shipping gives you a feedback loop. No launch means no signups, no churn, no support tickets, nothing to react to. You are building in a vacuum and telling yourself the reviewer will come through. Some mornings I believe it more than others.
What I am doing instead of refreshing the dashboard
Building the parts that do not need approval. The scheduler, the queue logic, the media handling, the multi account model. None of that cares whether Meta said yes. When approval lands I want zero days between "approved" and "live."
Going deep on the platform that already works. Not every integration is gated the same way. I would rather ship a tool that does one platform properly than a tool that does five platforms in theory.
Betting on a niche the gatekeepers do not control. PostSider is aimed at agencies and at AI agent workflows, meaning the publishing step at the end of an automated content pipeline. That positioning matters here, because agent-driven publishing is a use case that barely existed when these API review processes were designed. It is also the reason I open sourced it under AGPL-3.0. If a platform decides my hosted product is a problem, the code does not disappear.
Keeping a second product alive. I also sell a desktop app, one time purchase, no platform review, no API gatekeeper. Around 400 trials, 3 sales, which is a humbling number but it is a number I control. Two products with completely different risk profiles was not a strategy at first. It is now.
The plan B I actually have
Self hosting. AGPL means anyone can run PostSider on their own infrastructure with their own API credentials. If my app never gets blessed by Meta, users who already have their own developer access can still use the product. That is a smaller business than the SaaS, but it is not zero, and it turns platform rejection from an extinction event into a bad quarter.
The honest version: plan B is worse than plan A. I am not going to pretend otherwise. It just is not nothing, and having it is why I can keep working on this instead of quietly abandoning it.
What I would tell past me
Start the API review process on day one, before the product is finished. The review is the long pole, not the code. I built first and applied second, and that ordering cost me 8 weeks
2 Likes
1 Comment
1 Comment
-
1
What stood out to me is that finishing the product and becoming able to launch it turned out to be two completely different milestones.
It's a good reminder that the critical path of a business isn't always where the engineering effort is. Sometimes it's determined by dependencies you don't control at all.
Quick win. Documentation for PostSider (my open-source, API-first social publishing platform for AI agents) is live, and the whole thing took me under 30 minutes.
The trick: I didn't sit down and write page after page. I just gave Mintlify access to my GitHub repo and let it work from the codebase. It pulled the structure, generated the pages, and produced something genuinely polished out of what was already there.
Docs are usually the task I keep pushing to someday. Watching it go from empty to live in half an hour, without me grinding through Markdown, was the first time documenting felt like the easy part of the project.
PostSider is AGPL-3.0, built so AI agents can publish to social platforms through a clean API. Now there's actually something to read if you want to plug it in.
Onto the next thing. Happy to talk stack if anyone's curious.
1 Like
Comment
Hey Indie Hackers,
I was browsing Higgsfield recently, checking out how they handle video content, when I stumbled upon a really slick feature: a tool that estimates the virality potential of a piece of content.
And you know what? It clicked. I immediately thought: I need this exact thing for Postsider.
As a data nerd, I just love these kinds of insights. It’s not just a gimmick; it’s a quick, actionable assessment of a post. It can tell you what to improve, what's working, and what’s likely to flop before you even hit publish. Even as an optional feature, it just brings so much value to the table.
So, I took that inspiration from Higgsfield and started hacking away to adapt it for written/social posts.
It is still a work in progress and officially coming soon, but the core logic is coming together beautifully.
I’m curious—how much do you rely on pre-publish feedback or AI scoring for your content? Would a "virality score" make you feel more confident before posting, or do you prefer to just trust your gut and ship it?
1 Like
Comment
Quick update from the workshop — figured I'd share where PostSider is at instead of sitting on it until some "big launch" moment.
Things are getting closer. The core is solid, and lately I've been heads-down wiring up the connections to different platforms and their app verification / review flows. That part never makes a good screenshot — it's reading API docs, submitting for review, waiting in a queue, re-reading the docs again — but every connector that finally clicks into place makes the whole thing feel more real.
And the more I build, the more it actually makes sense. Early on there were moments where I wasn't sure if I was solving a real problem or just enjoying the engineering. Now the shape of it is clear: a clean publishing layer that you — or your agents — can actually talk to, without fighting five different dashboards.
As a solo founder, it's easy to pour all your energy into complaining. About platform providers. About review processes. About doing every single thing yourself. I've done my share of that. But honestly, the only real antidote is shipping the next piece. Less venting, more committing.
So that's the behind-the-scenes: not finished yet, but closer every week. More connectors live, more of the API surface stable, and a growing feeling that this is genuinely worth finishing.
More soon.
1 Like
Comment
About
I am building this app to make publishing and creating social media content easier, and I simply want a bridge to connect all my social media platforms in one place with easy access via API or MCP.



Comment