Content API Beats Clicking Publish: Why I Stopped Using the UI
Source: Dev.to
Why I Stopped Using the UI
I haven’t clicked Publish in three weeks. My blog has more posts than ever.
When you run one product, the editor workflow makes sense: open the dashboard, write, click Publish, done. That’s maybe five minutes of overhead.
But I run 14 products, each with its own blog on its own domain. Each blog needs fresh content for SEO, AI visibility, and staying alive in search results. Multiply that five‑minute overhead by 14 and you’re spending an hour just navigating dashboards before you’ve written a single word.
The Content API Solution
Instead of clicking through a UI, you POST a JSON payload to an endpoint and the blog post appears on your site.
curl -X POST https://yourproduct.com/api/blog/publish \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "How We Reduced Load Time by 40%",
"slug": "reduced-load-time-40-percent",
"content": "## The bottleneck was...",
"author": "Jakub",
"status": "published",
"tags": ["performance", "optimization"],
"meta_description": "A quick walkthrough of..."
}'
No clicking, no autosave delays, no “are you sure?” modals. The post is live.
How It Works in My Stack
- Backend – An Edge Function (Supabase) validates the payload, inserts into the
blog_poststable, and returns the slug. - Frontend – Already knows how to render posts from the database, so there’s no extra deployment step.
Practical Tips
Token Rotation
Never hard‑code a permanent token. Rotate it weekly with a cron job that generates a new token, stores it encrypted, and lets the old one expire.
Idempotency by Slug
If you POST twice with the same slug, the second call should update the existing post, not create a duplicate.
INSERT INTO blog_posts (slug, title, content, author, status)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (slug)
DO UPDATE SET title = $2, content = $3, updated_at = now();
Rate Limiting
Even on a private API, protect against accidental bursts (e.g., 47 rapid calls while debugging). A simple rate limiter prevents unintended duplicate publications.
Bash Wrapper for One‑Click Publishing
#!/bin/bash
PRODUCT=$1
SLUG=$2
CONTENT_FILE=$3
# Publish
curl -s -X POST "https://$PRODUCT/api/blog/publish" \
-H "Authorization: Bearer $(vault_token $PRODUCT)" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$(head -1 $CONTENT_FILE)" \
--arg s "$SLUG" \
--arg c "$(tail -n +3 $CONTENT_FILE)" \
'{title:$t, slug:$s, content:$c, status:"published"}')"
# Verify sitemap
sleep 5
curl -s "https://$PRODUCT/sitemap.xml" | grep -q "$SLUG" \
&& echo "Sitemap OK" || echo "WARN: slug not in sitemap"
# Request indexing (GSC API)
gsc_index "https://$PRODUCT/blog/$SLUG"
Usage: publish.sh
The script publishes the post, verifies the sitemap, and requests indexing—turning a 10‑minute manual process into ~10 seconds.
When the UI Is Still Useful
| Situation | Reason |
|---|---|
| Visual‑heavy posts | Custom layouts, embedded widgets, or interactive elements are easier to assemble in a WYSIWYG editor. |
| First post on a new product | Clicking through the editor helps you discover the blog’s look and feel. |
| Collaboration posts | Shared editors with commenting are better for review than a git‑based flow. |
Results
- After switching to the API, I published more blog posts across my products in one month than in the previous three months combined.
- The friction of “I should write a post” dropped from ~20 minutes of UI navigation to ~30 seconds of a single command.
- Building the Content API was a weekend project; the ROI was evident within the first week.
Closing Thoughts
If you manage multiple products—especially on a stack like Supabase + React—building a Content API can dramatically streamline your publishing workflow. The same pattern powers the blogs for tools like Audit Vibe Coding (code quality) and Be Recommended (AI visibility tracking). One script, many domains, consistent results.