Every list of "best social media tools" already has twenty entries. If you are building alone, entering that market needs a better reason than "mine will be nicer".
This is the reason I settled on, and the first part of a series where I go through Clienzo one piece at a time.
Who it is for
I did not want to build for marketing teams with approval chains. Clienzo is for people who post for themselves or a handful of clients: a founder announcing a launch, a freelancer running three clients' accounts, a small agency that wants each client kept separate.
Those people have one thing in common. Posting is not their job. It is the thing between them and their actual job.
The narrow bet
Most schedulers are built around their own composer. You open the app, write, pick accounts, schedule. That works, and Clienzo has it too.
The bet is that more and more writing does not start in a scheduler. It starts in a chat with an AI assistant, in a changelog, in a script that runs when a release is tagged. So Clienzo is built to be driven from outside:
- A public REST API, so anything that can make an HTTP request can schedule a post.
- An MCP server, so an assistant like Claude can create, schedule and retry posts from the same conversation where the post was written.
- Chat apps as channels. Discord, Telegram, Slack and Viber are first-class destinations, next to Facebook, Instagram, Threads, LinkedIn and the rest.
Sixteen networks are live today. Each one turned out to have its own rules, quirks and review process — which is most of what this series is about.
What I want to be honest about
A scheduler is only useful if you can trust it. So two rules shaped the product early:
- Every network gets its own result. A post that went out on five networks and failed on one says exactly that, and lets you retry just the one.
- No made-up numbers. If a network does not report views for a post, the analytics show a blank, not an estimate.
Both rules cost more work than the alternative. Both come up again in later parts.
What comes next
Tomorrow: the composer, and why "write once, post everywhere" is really "write once, then satisfy sixteen different sets of rules".
Originally published on jonasnguyen.com, where I write about building Clienzo and the next startups.
Top comments (8)
Building for founders and freelancers who juggle a few clients is a clear angle, since they feel the cost of switching tools more than any team does. The narrow bet on being driven from outside the composer is what would make me try it over the twenty others. Which of your first users came through the API rather than the app?
Thanks! Still early, but yes: some of the first users never touched the composer. They came in through the API and post from n8n: a workflow builds the post, calls Clienzo, and it just runs.
Those accounts post far more often than the ones using the app. That's the bet from part 1 showing up early: for some people the scheduler isn't a place you visit, it's a step in an automation. It's too soon to call it a pattern, but it's why the API got guardrails like idempotency keys, a daily cap and a dry run first.
Idempotency keys and a dry run are sensible defaults for people wiring a scheduler into n8n. Do those API users run into the daily cap often, or does it mostly sit unused?
Mostly unused on paid plans: it's there for runaway loops. On the free plan it's low on purpose, and one n8n user has already hit it. That made me realise I wasn't logging refusals, so I just shipped that, plus an in-app + email heads-up the first time a day you hit the cap, so a 429 in an n8n run isn't a silent mystery. Your question is literally why that exists.
Logging refusals is a good catch, and the heads-up on the first cap hit will save people a lot of guessing. Do you show the reset time in the message so someone running a workflow knows when it will work again?
Yes, in a few places. The heads-up says when it works again ("refused until Fri, 23 Oct 2026 00:00 UTC"; the count resets at midnight UTC), and the 429 itself carries the reset time in its message, so it shows up right in the failed n8n node.
For workflows that want to check before they hit it: GET /v1/me returns apiPostsToday and usageResetsAt, and a dry_run create tells you wouldExceedDailyCap plus the reset time without posting anything.
Your question also made me notice the daily-cap 429 didn't send a Retry-After header, only the per-minute limits did. That's the standard way for a tool to wait on its own, so I just added it: the 429 now carries Retry-After (seconds until the reset) and a resetsAt field in the error body. Thanks for the nudge.
the "blank, not an estimate" rule is the one i'd defend too, but i think it creates its own small support problem: someone sees an empty views cell for one network next to numbers for the others and assumes that post failed. do you show why it's blank (network doesn't report it vs not fetched yet), or leave it empty and let the per network result explain it?
You're right, and that exact confusion is why it's not left empty. There are two different "nothing"s, and each looks different:
And "did it fail?" never comes from Analytics: a post that didn't go out everywhere lands in a Failed tab with the network's own error. So a blank only ever means "no number exists", never "something went wrong". The legend under the table literally says "never zero".