Get Medium data with one API
The Medium API returns author and article data as clean JSON.
20 active endpoints. Every call is 1 credit.
- POST/medium/v1/user
- POST/medium/v1/user_id
- POST/medium/v1/user_articles
- POST/medium/v1/user_top_articles
- POST/medium/v1/article
- POST/medium/v1/article_content
- POST/medium/v1/article_html
- +13 more
What Medium endpoints does ReefAPI ship?
20 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Medium API
3 of 20 endpoints, ready to run
Public Medium user profile by username.
// Press "Try it" and this pane shows exactly what the // live site returned this second — including an empty // result, if that is the truth. No key, no account.
How the Medium API works
Medium is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 185 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Medium ids, timestamps and the paywall you cannot see
Medium has no paywall flag in this response, two different date formats depending on which action you call, and two different pagination cursor shapes. Measured 2026-08-27 against @dhh, the Signal v. Noise publication and the python and machine-learning tag feeds.
| Field | What it holds | Measured 2026-08-27 |
|---|---|---|
| Article id | 12 lowercase hex characters, the tail of the URL slug | 41adf356857f, from .../reconsider-41adf356857f |
| user_id and collection_id | The same 12-hex shape as an article id | dhh is 54bcbf647830; Signal v. Noise is 668e14b18fb1 |
| published_at and created_at | Unix epoch MILLISECONDS, not seconds | 1446644507775 is 2015-11-04 |
| published_at from the tag action | An RFC-822 date string instead, because that surface is the topic feed | "Wed, 26 Aug 2026 22:02:12 GMT" |
| reading_time | Fractional minutes, not a rounded integer | 11.599056603773585 on a 2,822-word post |
| word_count against the returned body | word_count is Medium's full count; a member-only post returns only a free preview | One tagged post: word_count 1,338 against 160 body words. Five siblings returned 98 to 101% |
| next_cursor on user_articles and publication_articles | An epoch-milliseconds string | "1545257107680" |
| next_cursor on article_responses | offset:id, a different shape entirely | "45:ade9442ee53d" |
| collection_id | Non-null means the post was published in a publication, and its URL sits under the publication path | RECONSIDER lives at /signal-v-noise/..., not /@dhh/... |
| Publication slug | Follows renames, so the returned slug can differ from the one you sent | slug "towards-data-science" came back as slug "data-science", name "TDS Archive" |
| Body formats | article_content, article_html and article_markdown return the same paragraphs in three encodings | Same post, 67 paragraphs: 16,272 chars plain, 16,689 HTML, 16,306 markdown |
publication.created_at came back null on all three publications measured, and publication.url is inconsistent: a custom-domain publication returned "betterprogramming.pub" with no scheme while medium.com-hosted ones returned a full https URL. Normalize it before using it as a link.
What people build with Medium
The jobs this data is most often used for.
endpoints
credit per call
Content research calls user_articles to study an author's output.
Author-intelligence uses user and user_top_articles to profile a writer.
RAG pipelines use article_content to ingest a post as clean text.
What Medium data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 185 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/medium/v1/user \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"user":"dhh"}'import requests
r = requests.post(
"https://api.reefapi.com/medium/v1/user",
headers={"x-api-key": REEF_KEY},
json={
"user": "dhh"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Medium.
Get a free key →What is a Medium post id and where do I find it?▾
It is the 12-character lowercase hex string at the end of every article URL. In https://medium.com/signal-v-noise/reconsider-41adf356857f the id is 41adf356857f. The article action takes either id or url, and on 2026-08-27 both returned identical objects. User ids and publication (collection) ids use the same 12-hex format, so a bare id on its own does not tell you what kind of object it points at.
Are Medium timestamps in seconds or milliseconds?▾
Milliseconds, on every action except one. created_at and published_at come back as epoch milliseconds, so 1446644507775 is 2015-11-04, and dividing by 1000 first is the usual fix for a date that lands in 1970. The exception is the tag action, which reads the topic feed and returns published_at as an RFC-822 string like "Wed, 26 Aug 2026 22:02:12 GMT". If you merge tag results with article results, normalize the dates first.
Is there a member-only or paywall flag on an article?▾
No. The article object has fourteen keys and none of them marks a post as member-only. What you can do is compare word_count against the body you actually got. On 2026-08-27, five of six posts pulled from the machine-learning feed returned 98 to 101% of their stated word_count, and the sixth returned 160 words against a word_count of 1,338. That twelve-percent ratio is the free preview of a locked post. paragraph_count in meta is a useful second signal: the truncated post had 9 paragraphs, the full ones had 54 and more.
Why is reading_time a decimal?▾
It is Medium's raw estimate in minutes and it is not rounded: a 2,822-word post returned 11.599056603773585 and a 564-word post returned 2.128301886792453. Round it yourself for display. The underlying arithmetic is roughly 265 words a minute plus image time, which is why it never lands on a whole number.
Why did user_articles return four articles when I asked for ten?▾
Because limit is an upper bound on one page of the profile stream, not a guarantee. Asking for 10 from @dhh returned 4 articles with has_more true and a next_cursor, even though that profile's posts_published_count is 191. Keep passing the previous response's next_cursor until has_more goes false. Ordering on page one is not strictly newest-first either: the first item returned was from 2015 and the second from 2019, because the profile's featured post leads the stream.
Does user_top_articles give me an author's all-time most-clapped posts?▾
No, and the difference matters. It sorts the same profile-stream page by clap count rather than asking Medium for a global ranking. Measured on @dhh, both actions returned the same four articles, with user_top_articles reordering them to 31,648 / 4,322 / 3,479 / 1,424 claps. For a genuine all-time top you need to page through user_articles with next_cursor and sort the full set yourself.
How do I tell an author's own post from one published in a publication?▾
Read collection_id. When it is null the post sits on the author's profile at medium.com/@handle. When it is set, the post was published in that publication and its URL uses the publication path: RECONSIDER carries creator_id 54bcbf647830 (dhh) and collection_id 668e14b18fb1, and lives at medium.com/signal-v-noise/reconsider-41adf356857f. The publication action turns a slug into that same id, so you can join the two.
What does a Medium response look like in the data?▾
A response is itself a post, not a comment record. Each one has its own 12-hex id, its own URL under the responder's handle, a clap count and a created_at in milliseconds. The title field is an auto-generated truncation of the opening line, so it often repeats the start of text. Responses page with a cursor shaped offset:id, for example "45:ade9442ee53d", which is a different format from the epoch cursor used by user_articles.
What is the Medium API?▾
Medium API is a ReefAPI endpoint group for medium It returns live JSON through POST requests under /medium/v1.
Is the Medium API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Medium calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Medium login or account?▾
No login to Medium is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Medium data?▾
The page example is captured from a live user call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Medium API use?▾
Medium actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Medium from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call medium actions with the same key, credit pool and JSON envelope used by normal REST requests.
10 Social Media APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Medium, you are one call away from the rest of the category — no second contract, no second integration.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 184 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts.