Publishing to dev.to Through Its API — What I Measured
Everything here was observed while publishing and updating articles on a real account, not read somewhere. Dates are given so you can judge how stale it is.
Measured between 2026-09-04 and 2026-09-06, across 19 articles and roughly 40 update calls.
Rate limiting returns 500, not 429
This is the one that costs the most time, because a 500 reads as "the server is broken" and invites a retry loop.
2026-09-04. Nine consecutive PUT /articles/:id calls with no delay:
3 of 9 -> HTTP 500
Nothing in the body says "rate limit". The same requests, replayed with a delay, all succeeded.
| spacing | calls | failures |
|---|---|---|
| none | 9 | 3 |
| 10 seconds | 6 | 0 |
| 10 seconds | 11 | 0 |
| 20 seconds | 7 | 0 |
Ten seconds between write calls was enough across every batch I ran. If you get a 500 on a write, wait before assuming the payload is at fault.
The cover image field has a different name on the way in and out
You set it as main_image. You read it back as cover_image.
request { "article": { "main_image": "https://example.github.io/covers/a.png" } }
response { "cover_image": "https://media2.dev.to/dynamic/image/width=1000,.../https%3A%2F%2F..." }
The response URL is dev.to's own CDN, rewritten from the one you sent. That matters: once dev.to has ingested the image, your host going down does not break the article.
If you check for main_image on the response, it is null, and it looks like
the write did nothing.
published is taken from the request, every time
There is no "leave it as it is". Whatever you send is what the article becomes.
PUT /articles/:id with published: false -> a live article is taken down
The URL survives, the page 404s, and links to it die. If your tool decides
published from a command-line flag, an update without that flag unpublishes
the article you meant to edit.
The safe shape is to refuse rather than guess:
if (existing?.published && !publish) {
throw new Error("This article is published. Updating without --publish takes it down.");
}
Guessing the intent is worse, because "meant to unpublish" and "forgot the flag" look identical from inside the tool.
The article detail response omits series
You can set series on the article object, and it works — but
GET /articles/:id does not return it.
I set a series on seven articles and checked the API. Nothing came back. The series box was rendering on the article page the whole time.
# does not tell you whether the series was set
curl -H "api-key: $KEY" https://dev.to/api/articles/4570263 | jq .series
# does
curl -s https://dev.to/<user>/<slug> | grep -o "<series name>"
If you want to know what is displayed, look at what is displayed.
Publishing several articles on one day buries most of them
Not an API behaviour, but it is the mistake the API makes easy.
2026-09-04. Nine English articles published within one day. Page views after 24 hours:
| article | views |
|---|---|
| 1st | 27 |
| 2nd | 23 |
| 3rd | 13 |
| 4th | 10 |
| remaining 5 | 0 |
The feed is chronological, so articles published together compete with each other and the later ones are never seen. One a day, from then on.
The ones that sat at zero views did not recover on their own.
Identity: use the id, not the title
GET /articles/me/published gives you your articles. If you find the existing
one by title, the day you fix a title-rendering bug is the day your tool stops
recognising its own articles and creates duplicates.
Keep a file mapping your filename to the id the API assigned:
{ "ids": { "composite-github-action": 4576296 } }
And stop when the id is recorded but not found. Silently falling through to create is the worst option: you end up with two published copies of the same article competing for the same search terms.
Notes
- The API is Forem API v1; the key goes in an
api-keyheader - Everything above is behaviour observed on one account. Rate limits in particular may differ by account age or reputation
- Where this disagrees with the official documentation, the documentation is the place to start; this page records what actually happened
The workflow itself is available
Quartet, the four-persona version, is published free under MIT. Quintet adds a UI Designer persona, review criteria, a per-Issue parallel execution script, and a 10-chapter guide.
See the free version Product page