Access Forem and DEV Community articles, users, comments, and other resources via a simple REST API.
Bring your own key. This API needs your own DEV Community key - get one from the provider, add it once below, and the proxy injects it on every call. Your OmniStream plan covers the unified SDK, key storage, and proxy - the provider's own rate limits still apply to your key.
This is a community listing. If you own this API, you can request ownership.
npm install omnistream-sdkimport { OmniClient } from "omnistream-sdk";
const omni = new OmniClient({ token: process.env.OMNI_KEY! });
// One key reaches every API on the marketplace.
const data = await omni.call("devto/getArticles");One install, one key - the same client calls every API on the marketplace.
Pagination page
Page size (the number of items to return per page). The default maximum value can be overridden by "API_PER_PAGE_MAX" environment variable.
Using this parameter will retrieve articles that contain the requested tag. Articles will be ordered by descending popularity.This parameter can be used in conjuction with `top`.
Using this parameter will retrieve articles with any of the comma-separated tags. Articles will be ordered by descending popularity.
Using this parameter will retrieve articles that do _not_ contain _any_ of comma-separated tags. Articles will be ordered by descending popularity.
Using this parameter will retrieve articles belonging to a User or Organization ordered by descending publication date. If `state=all` the number of items returned will be `1000` instead of the default `30`. This parameter can be used in conjuction with `state`.
Using this parameter will allow the client to check which articles are fresh or rising. If `state=fresh` the server will return fresh articles. If `state=rising` the server will return rising articles. This param can be used in conjuction with `username`, only if set to `all`.
Using this parameter will allow the client to return the most popular articles in the last `N` days. `top` indicates the number of days since publication of the articles returned. This param can be used in conjuction with `tag`.
Adding this will allow the client to return the list of articles belonging to the requested collection, ordered by ascending publication date.
Published articles
Publish article
Published articles sorted by published date
User's articles
User's all articles
User's published articles
/**
* DEVCommunity - generated by OmniStream from DEV Community's OpenAPI spec.
* One typed method per endpoint. A single Omni key reaches the API.
*/
const DEFAULT_BASE = "https://grid.skinvaults.online/v1/proxy/devto";
export class DEVCommunityError extends Error {
status: number;
code?: string;
constructor(status: number, code: string | undefined, message?: string) {
super(message || `DEVCommunity error ${status}`);
this.name = "DEVCommunityError";
this.status = status;
this.code = code;
}
}
export interface DEVCommunityOptions {
baseUrl?: string;
fetch?: typeof fetch;
timeoutMs?: number;
}
export class DEVCommunity {
/** @param token Your OmniStream key (one key for every API). */
constructor(private token: string, private opts: DEVCommunityOptions = {}) {
if (!token) throw new Error("DEVCommunity: token is required");
}
rateLimit: { remainingMinute?: number; remainingDay?: number } | null = null;
private async _request(method: string, path: string, { params, body }: { params?: Record<string, unknown>; body?: unknown } = {}): Promise<any> {
const f = this.opts.fetch ?? globalThis.fetch;
const url = new URL((this.opts.baseUrl ?? DEFAULT_BASE).replace(/\/+$/, "") + path);
if (params) for (const [k, v] of Object.entries(params)) if (v != null) url.searchParams.set(k, String(v));
const headers: Record<string, string> = { "x-omni-key": this.token };
if (body !== undefined) headers["content-type"] = "application/json";
const res = await f(url, { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined });
this.rateLimit = {
remainingMinute: Number(res.headers.get("x-ratelimit-remaining-minute")) || undefined,
remainingDay: Number(res.headers.get("x-ratelimit-remaining-day")) || undefined,
};
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new DEVCommunityError(res.status, data?.error?.code, data?.error?.message);
return data.data ?? data;
}
/** Published articles */
getArticles(params: { "page"?: number; "per_page"?: number; "tag"?: string; "tags"?: string; "tags_exclude"?: string; "username"?: string; "state"?: string; "top"?: number; "collection_id"?: number }): Promise<any> {
return this._request("GET", "/api/articles", { params });
}
/** Publish article */
createArticle(body: unknown): Promise<any> {
return this._request("POST", "/api/articles", { body });
}
/** Published articles sorted by published date */
getLatestArticles(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/articles/latest", { params });
}
/** User's articles */
getUserArticles(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/articles/me", { params });
}
/** User's all articles */
getUserAllArticles(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/articles/me/all", { params });
}
/** User's published articles */
getUserPublishedArticles(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/articles/me/published", { params });
}
/** User's unpublished articles */
getUserUnpublishedArticles(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/articles/me/unpublished", { params });
}
/** Published article by id */
getArticleById(params: { "id": number }): Promise<any> {
return this._request("GET", "/api/articles/{id}", { params });
}
/** Update an article by id */
updateArticle(body: unknown, params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/articles/{id}", { body, params });
}
/** Unpublish an article */
unpublishArticle(params: { "id": number; "note"?: string }): Promise<any> {
return this._request("PUT", "/api/articles/{id}/unpublish", { params });
}
/** Published article by path */
getArticleByPath(params: { "username": string; "slug": string }): Promise<any> {
return this._request("GET", "/api/articles/{username}/{slug}", { params });
}
/** Comments */
getCommentsByArticleId(params: { "a_id"?: string; "p_id"?: string }): Promise<any> {
return this._request("GET", "/api/comments", { params });
}
/** Comment by id */
getCommentById(params: { "id": number }): Promise<any> {
return this._request("GET", "/api/comments/{id}", { params });
}
/** display ads */
getapiDisplayAds(): Promise<any> {
return this._request("GET", "/api/display_ads", {});
}
/** display ads */
postapiDisplayAds(body: unknown): Promise<any> {
return this._request("POST", "/api/display_ads", { body });
}
/** display ad */
getapiDisplayAdsId(params: { "id": number }): Promise<any> {
return this._request("GET", "/api/display_ads/{id}", { params });
}
/** display ads */
putapiDisplayAdsId(body: unknown, params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/display_ads/{id}", { body, params });
}
/** unpublish */
putapiDisplayAdsIdUnpublish(params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/display_ads/{id}/unpublish", { params });
}
/** Followers */
getFollowers(params: { "page"?: number; "per_page"?: number; "sort"?: string }): Promise<any> {
return this._request("GET", "/api/followers/users", { params });
}
/** Followed Tags */
getFollowedTags(): Promise<any> {
return this._request("GET", "/api/follows/tags", {});
}
/** An organization */
getOrganization(params: { "username": string }): Promise<any> {
return this._request("GET", "/api/organizations/{username}", { params });
}
/** Organization's Articles */
getOrgArticles(params: { "username": string; "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/organizations/{username}/articles", { params });
}
/** Organization's users */
getOrgUsers(params: { "username": string; "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/organizations/{username}/users", { params });
}
/** show details for all pages */
getapiPages(): Promise<any> {
return this._request("GET", "/api/pages", {});
}
/** pages */
postapiPages(body: unknown): Promise<any> {
return this._request("POST", "/api/pages", { body });
}
/** show details for a page */
getapiPagesId(params: { "id": number }): Promise<any> {
return this._request("GET", "/api/pages/{id}", { params });
}
/** update details for a page */
putapiPagesId(body: unknown, params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/pages/{id}", { body, params });
}
/** remove a page */
deleteapiPagesId(params: { "id": number }): Promise<any> {
return this._request("DELETE", "/api/pages/{id}", { params });
}
/** Podcast Episodes */
getPodcastEpisodes(params: { "page"?: number; "per_page"?: number; "username"?: string }): Promise<any> {
return this._request("GET", "/api/podcast_episodes", { params });
}
/** A Users or organizations profile image */
getProfileImage(params: { "username": string }): Promise<any> {
return this._request("GET", "/api/profile_images/{username}", { params });
}
/** create reaction */
postapiReactions(params: { "category": string; "reactable_id": number; "reactable_type": string }): Promise<any> {
return this._request("POST", "/api/reactions", { params });
}
/** toggle reaction */
postapiReactionsToggle(params: { "category": string; "reactable_id": number; "reactable_type": string }): Promise<any> {
return this._request("POST", "/api/reactions/toggle", { params });
}
/** Readinglist */
getReadinglist(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/readinglist", { params });
}
/** Tags */
getTags(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/tags", { params });
}
/** The authenticated user */
getUserMe(): Promise<any> {
return this._request("GET", "/api/users/me", {});
}
/** A User */
getUser(params: { "id": string }): Promise<any> {
return this._request("GET", "/api/users/{id}", { params });
}
/** Suspend a User */
suspendUser(params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/users/{id}/suspend", { params });
}
/** Unpublish a User's Articles and Comments */
unpublishUser(params: { "id": number }): Promise<any> {
return this._request("PUT", "/api/users/{id}/unpublish", { params });
}
/** Articles with a video */
videos(params: { "page"?: number; "per_page"?: number }): Promise<any> {
return this._request("GET", "/api/videos", { params });
}
}
export default DEVCommunity;
No reviews yet. Be the first to rate this API.
Yes. DEV Community uses apiKey authentication, so you bring your own key from the provider. You store it once on OmniStream and the proxy injects it into every call, so your code only ever sends your Omni key.
Access Forem and DEV Community articles, users, comments, and other resources via a simple REST API. It exposes 39 endpoints over GET, POST, PUT, DELETE, including GET /api/articles, POST /api/articles, GET /api/articles/latest.
Install the OmniStream SDK for your language and call DEV Community through it. The client is generated from this API's OpenAPI spec, so parameters and responses are fully typed, and the same client also calls every other API in the marketplace.
You can start on the free plan. OmniStream charges for the unified SDK, key storage and proxy rather than for DEV Community itself, and DEV Community's own rate limits still apply to your provider key.
NYTimes Books: The Books API provides information about book reviews and The New York Times bestsellers lists.
User's unpublished articles
Published article by id
Update an article by id
Unpublish an article
Published article by path
Comments
Comment by id
display ads
display ads
display ad
display ads
unpublish
Followers
Followed Tags
An organization
Organization's Articles
Organization's users
show details for all pages
pages
show details for a page
update details for a page
remove a page
Podcast Episodes
A Users or organizations profile image
create reaction
toggle reaction
Readinglist
Tags
The authenticated user
A User
Suspend a User
Unpublish a User's Articles and Comments
Articles with a video