# Medium API scraper — Medium.com articles (full text, HTML & markdown), author profiles, publications, responses, tags and search, no account needed

> Public Medium user profile by username.
> ReefAPI engine `medium` · 20 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/medium/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed or blocked calls are free.
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /medium/v1/user — 1 credit
Public Medium user profile by username.

**Parameters:**
- `user` (string, required) — Medium username, with or without the leading @ (the name in medium.com/@<user>).

**Returns:** user{} — user_id, username, name, bio, followers_count, following_count, posts_published_count, author_tags[]

**Example request body:**
```json
{
  "user": "dhh"
}
```

### POST /medium/v1/user_id — 1 credit
Resolve username to Medium userId.

**Parameters:**
- `user` (string, required) — Medium username, with or without the leading @ (the name in medium.com/@<user>).

**Returns:** user_id, username

**Example request body:**
```json
{
  "user": "dhh"
}
```

### POST /medium/v1/user_articles — 1 credit
An author's published articles, newest first, with deep pagination.

**Parameters:**
- `user` (string, required) — Medium username, with or without the leading @ (the name in medium.com/@<user>).
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** articles[] (id, title, claps, reading_time, url, tags), next_cursor, has_more

**Example request body:**
```json
{
  "user": "dhh"
}
```

### POST /medium/v1/user_top_articles — 1 credit
User articles sorted by clap count from profile references.

**Parameters:**
- `user` (string, required) — Medium username, with or without the leading @ (the name in medium.com/@<user>).
- `limit` (integer, optional, default 25) — Max items to return (1-50). Larger values are clamped to 50.

**Returns:** articles[] — the user's articles sorted by clap count (descending)

**Example request body:**
```json
{
  "user": "dhh"
}
```

### POST /medium/v1/article — 1 credit
Article metadata by url or id.

**Parameters:**
- `url` (string, optional) — Full article URL (alternative to id).
- `id` (string, optional) — Article post id — the 12-char hex at the end of an article URL. Provide id OR url.

**Returns:** article{} — id, title, subtitle, claps, reading_time, word_count, published_at, url, tags, creator_id, responses_count

### POST /medium/v1/article_content — 1 credit
Article plain-text body from bodyModel paragraphs.

**Parameters:**
- `url` (string, optional) — Full article URL (alternative to id).
- `id` (string, optional) — Article post id — the 12-char hex at the end of an article URL. Provide id OR url.

**Returns:** article{}, body (plain text), paragraph_count

### POST /medium/v1/article_html — 1 credit
Article HTML body from bodyModel paragraphs.

**Parameters:**
- `url` (string, optional) — Full article URL (alternative to id).
- `id` (string, optional) — Article post id — the 12-char hex at the end of an article URL. Provide id OR url.

**Returns:** article{}, body (HTML), paragraph_count

### POST /medium/v1/article_markdown — 1 credit
Article markdown body from bodyModel paragraphs.

**Parameters:**
- `url` (string, optional) — Full article URL (alternative to id).
- `id` (string, optional) — Article post id — the 12-char hex at the end of an article URL. Provide id OR url.

**Returns:** article{}, body (markdown), paragraph_count

### POST /medium/v1/article_responses — 1 credit
Public responses/comments for an article.

**Parameters:**
- `url` (string, optional) — Full article URL (alternative to id).
- `id` (string, optional) — Article post id — the 12-char hex at the end of an article URL. Provide id OR url.
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** responses[] (id, title, text, claps, author_username, created_at, url), next_cursor, has_more

### POST /medium/v1/publication — 1 credit
Publication/collection metadata by slug.

**Parameters:**
- `slug` (string, required) — Publication slug — the path segment in medium.com/<slug> (or its custom-domain handle).

**Returns:** publication{} — id, name, slug, description, url, subscriber_count, created_at

### POST /medium/v1/publication_id — 1 credit
Resolve publication slug to collection id.

**Parameters:**
- `slug` (string, required) — Publication slug — the path segment in medium.com/<slug> (or its custom-domain handle).

**Returns:** publication_id, slug

### POST /medium/v1/publication_articles — 1 credit
A publication's articles, newest first, with deep pagination.

**Parameters:**
- `slug` (string, required) — Publication slug — the path segment in medium.com/<slug> (or its custom-domain handle).
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** articles[] (id, title, claps, url, tags), next_cursor, has_more

### POST /medium/v1/tag — 1 credit
Latest posts for a topic tag (the tag/topic feed).

**Parameters:**
- `tag` (string, required) — Medium topic tag slug (e.g. python, machine-learning).
- `limit` (integer, optional, default 10) — Max items to return (1-25). Larger values are clamped to 25.

**Returns:** tag, posts[] (id, title, url, published_at, creator, description)

**Example request body:**
```json
{
  "tag": "python"
}
```

### POST /medium/v1/search_users — 1 credit
Look up an author by exact username. (Medium gates fuzzy people-search behind a logged-in JS app, so this resolves q as a username and returns that profile.)

**Parameters:**
- `q` (string, required) — Search term.

**Returns:** users[] — the profile whose username equals q (id, name, bio, follower counts)

### POST /medium/v1/search_publications — 1 credit
Look up a publication by exact slug. (Fuzzy publication search is login/JS-gated on Medium, so this resolves q as a publication slug and returns that publication.)

**Parameters:**
- `q` (string, required) — Search term.

**Returns:** publications[] — the publication whose slug equals q

### POST /medium/v1/search_tags — 1 credit
Check whether a topic tag exists and is active on Medium (resolves q as a tag slug).

**Parameters:**
- `q` (string, required) — Search term.

**Returns:** tags[] — [{slug, sample_posts}] (sample_posts > 0 means the tag is live)

### POST /medium/v1/followers — 1 credit
An author's followers (paginated). Identify the author by 'user' or 'user_id'.

**Parameters:**
- `user` (string, optional) — Medium username (with/without @). Provide user OR user_id.
- `user_id` (string, optional) — Medium numeric/hash user id (a profile's user_id). Provide user_id OR user.
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** followers[] (user_id, username, name, bio), next_cursor, has_more

### POST /medium/v1/following — 1 credit
The authors a user follows (paginated). Identify the user by 'user' or 'user_id'.

**Parameters:**
- `user` (string, optional) — Medium username (with/without @). Provide user OR user_id.
- `user_id` (string, optional) — Medium numeric/hash user id (a profile's user_id). Provide user_id OR user.
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** following[] (user_id, username, name, bio), next_cursor, has_more

### POST /medium/v1/list — 1 credit
Reading list metadata and articles from public list page HTML. Provide the full list 'url', or 'id' together with 'user'.

**Parameters:**
- `id` (string, optional) — Reading-list id (the trailing id in a list URL). Provide with 'user', or instead pass the full list 'url'.
- `url` (string, optional) — Full reading-list URL (alternative to user + id).
- `user` (string, optional) — List owner's username (with/without @; also accepted as 'username'). Combine with id, or pass the full url.
- `slug` (string, optional) — Optional list slug (the human-readable part of a list URL).
- `limit` (integer, optional, default 25) — Max items to return (1-50). Larger values are clamped to 50.

**Returns:** list{id, url, name, article_count}, articles[] (id, url)

### POST /medium/v1/search_articles — 1 credit
Search Medium articles by keyword — returns matching articles with title, URL and publication details from medium.com.

**Parameters:**
- `q` (string, required) — Search term.
- `limit` (integer, optional, default 10) — Max items to return (1-50). Larger values are clamped to 50.
- `cursor` (string, optional) — Pagination cursor from a previous response's next_cursor. Omit for page one.

**Returns:** articles[] (id, title, slug, url), query, next_cursor, has_more

## More
- Try it live, no code: https://reefapi.com/playground?engine=medium
- Human docs page: https://reefapi.com/docs/medium
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
