Skip to content

Why our API supports writes everywhere, not just reads

I have spent more weekends than I care to admit gluing tools together with nightly scripts because the API I wanted to write against did not let me. Stripe sends a webhook when a subscription renews. My old billing tool would happily let me read the customer record, the invoice template, the rate cards. It would not let me create the invoice from outside, set its VAT code, attach the right PDF template, or push it to a customer portal in a non-default state.

So I ended up writing a script that did roughly half the work, exported the rest as a CSV, and uploaded that CSV into the tool by hand. That is not automation. That is a part-time admin job dressed up in a cron expression.

If you read enough of these stories, a pattern emerges. Most “APIs” in the SaaS world are really read APIs with a thin write surface bolted on for the most obvious cases: create a contact, create a single invoice from a template, mark a payment received. The moment you want to do something more specific, like creating an invoice with a custom number, a per-line VAT code, and a non-default email template, the write surface runs out. You can read your way around the problem, but you cannot solve it. The connector marketplace papers over this for common integrations, which is why everyone has a Zapier story, but you cannot build an actual custom flow on top.

I built Rozuro on the opposite premise. Every action that exists in the UI is also a REST endpoint. The same auth, the same validation, the same ledger writes. There is no shadow API that does more than the public one, and the UI is not allowed to do anything the API cannot. That sounds boring as a marketing line, and it is. As an engineering choice it changes what you can build.

The concrete example I keep coming back to. Stripe webhook fires on a subscription renewal. A small Node script reads the event, calls the Rozuro API to create a new invoice with the right number sequence, the right VAT code based on the customer’s country, and a custom email template that includes the subscription period. The same script posts the resulting PDF URL back to the customer portal. The whole thing is forty lines of code and zero spreadsheets. The Rozuro side runs through exactly the same validation as a human clicking through the UI. The ledger writes are identical. If an audit comes in five years later, the invoice looks indistinguishable from one I would have made by hand.

The principle that pays off is harder to explain than the example, but it goes like this: write parity means there is no privileged interface. The UI is just one client among many. Your scripts are first-class citizens. You can build the workflow that fits your business instead of bending your business to the workflow the SaaS happens to support. That is what an API should give you, and what most of them quietly do not.

There are honest gaps. We do not yet have an OpenAPI spec for every endpoint (it is in the works, the schemas are stable enough now to publish). Some of the more exotic resources have endpoints that need cleaning up before they are documented. The webhook signing scheme is the standard HMAC-SHA256 over the raw payload, which is fine, but the docs around verifying it could be better. None of those things are why we built it. They are just what is on the list to polish.

If you have an automation you have always wanted to build but never could because the API ran out of room, that is exactly the conversation I want to have — contact us.

Love, Marten.