Find an API

Search public APIs with auth details & Postman guides

← All APIs

Forem API V1

dev · Social

Social No Auth Free & Open social

Access Forem articles, users and other resources via API. For a real-world example of Forem in action, check out [DEV](https://www.dev.to). All endpoints can be accessed with the 'api-key' header and a accept header, but some of them are accessible publicly without authentication. Dates and date times, unless otherwise specified, must be in the [RFC 3339](https://tools.ietf.org/html/rfc3339) format.

Authentication

No authentication requiredFree to use with no key needed.

Sample Requests

GET Published articles

This endpoint allows the client to retrieve a list of articles. "Articles" are all the posts that users create on DEV that typically show up in the feed. They can be a blog post, a discussion question, a help thread etc. but is referred to as article within the code. By default it will return feat

https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles?tag=example&top=1&page=1&tags=example&state=fresh&per_page=30&username=testuser&tags_exclude=example&collection_id=1

Hover any highlighted part to learn what it does

curl -X GET "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles?tag=example&top=1&page=1&tags=example&state=fresh&per_page=30&username=testuser&tags_exclude=example&collection_id=1"
import requests
params = {
    "tag": "example",
    "top": "1",
    "page": "1",
    "tags": "example",
    "state": "fresh",
    "per_page": "30",
    "username": "testuser",
    "tags_exclude": "example",
    "collection_id": "1"
}
response = requests.get(
    "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles",
    params=params,
)
print(response.json())
const url = new URL('https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles');
url.searchParams.set('tag', 'example');
url.searchParams.set('top', '1');
url.searchParams.set('page', '1');
url.searchParams.set('tags', 'example');
url.searchParams.set('state', 'fresh');
url.searchParams.set('per_page', '30');
url.searchParams.set('username', 'testuser');
url.searchParams.set('tags_exclude', 'example');
url.searchParams.set('collection_id', '1');

const response = await fetch(url); 
const data = await response.json();
console.log(data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL, _ := url.Parse("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles")
	q := baseURL.Query()
	q.Set("tag", "example")
	q.Set("top", "1")
	q.Set("page", "1")
	q.Set("tags", "example")
	q.Set("state", "fresh")
	q.Set("per_page", "30")
	q.Set("username", "testuser")
	q.Set("tags_exclude", "example")
	q.Set("collection_id", "1")
	baseURL.RawQuery = q.Encode()
	targetURL := baseURL.String()
	req, _ := http.NewRequest("GET", targetURL, nil)

	client := &http.Client{}
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "json"

uri = URI("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles")
uri.query = URI.encode_www_form({
  "tag" => "example",
  "top" => "1",
  "page" => "1",
  "tags" => "example",
  "state" => "fresh",
  "per_page" => "30",
  "username" => "testuser",
  "tags_exclude" => "example",
  "collection_id" => "1"
})

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"

req = Net::HTTP::Get.new(uri)

res = http.request(req)
puts JSON.parse(res.body)
<?php
$url = "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/articles?" . http_build_query([
    "tag" => "example",
    "top" => "1",
    "page" => "1",
    "tags" => "example",
    "state" => "fresh",
    "per_page" => "30",
    "username" => "testuser",
    "tags_exclude" => "example",
    "collection_id" => "1"
]);
$opts = ["http" => [
    "method" => "GET",
]];
$ctx = stream_context_create($opts);
$res = file_get_contents($url, false, $ctx);
print_r(json_decode($res, true));
GET Comments

This endpoint allows the client to retrieve all comments belonging to an article or podcast episode as threaded conversations. It will return the all top level comments with their nested comments as threads. See the format specification for further details.

https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments?a_id=example&p_id=example

Hover any highlighted part to learn what it does

curl -X GET "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments?a_id=example&p_id=example"
import requests
params = {
    "a_id": "example",
    "p_id": "example"
}
response = requests.get(
    "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments",
    params=params,
)
print(response.json())
const url = new URL('https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments');
url.searchParams.set('a_id', 'example');
url.searchParams.set('p_id', 'example');

const response = await fetch(url); 
const data = await response.json();
console.log(data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL, _ := url.Parse("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments")
	q := baseURL.Query()
	q.Set("a_id", "example")
	q.Set("p_id", "example")
	baseURL.RawQuery = q.Encode()
	targetURL := baseURL.String()
	req, _ := http.NewRequest("GET", targetURL, nil)

	client := &http.Client{}
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "json"

uri = URI("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments")
uri.query = URI.encode_www_form({
  "a_id" => "example",
  "p_id" => "example"
})

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"

req = Net::HTTP::Get.new(uri)

res = http.request(req)
puts JSON.parse(res.body)
<?php
$url = "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/comments?" . http_build_query([
    "a_id" => "example",
    "p_id" => "example"
]);
$opts = ["http" => [
    "method" => "GET",
]];
$ctx = stream_context_create($opts);
$res = file_get_contents($url, false, $ctx);
print_r(json_decode($res, true));
GET Podcast Episodes

This endpoint allows the client to retrieve a list of podcast episodes. "Podcast episodes" are episodes belonging to podcasts. It will only return active (reachable) podcast episodes that belong to published podcasts available on the platform, ordered by descending publication date.

https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes?page=1&per_page=30&username=testuser

Hover any highlighted part to learn what it does

curl -X GET "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes?page=1&per_page=30&username=testuser"
import requests
params = {
    "page": "1",
    "per_page": "30",
    "username": "testuser"
}
response = requests.get(
    "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes",
    params=params,
)
print(response.json())
const url = new URL('https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes');
url.searchParams.set('page', '1');
url.searchParams.set('per_page', '30');
url.searchParams.set('username', 'testuser');

const response = await fetch(url); 
const data = await response.json();
console.log(data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
)

func main() {
	baseURL, _ := url.Parse("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes")
	q := baseURL.Query()
	q.Set("page", "1")
	q.Set("per_page", "30")
	q.Set("username", "testuser")
	baseURL.RawQuery = q.Encode()
	targetURL := baseURL.String()
	req, _ := http.NewRequest("GET", targetURL, nil)

	client := &http.Client{}
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
require "net/http"
require "json"

uri = URI("https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes")
uri.query = URI.encode_www_form({
  "page" => "1",
  "per_page" => "30",
  "username" => "testuser"
})

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"

req = Net::HTTP::Get.new(uri)

res = http.request(req)
puts JSON.parse(res.body)
<?php
$url = "https://api.apis.guru/v2/specs/dev.to/1.0.0/api/podcast_episodes?" . http_build_query([
    "page" => "1",
    "per_page" => "30",
    "username" => "testuser"
]);
$opts = ["http" => [
    "method" => "GET",
]];
$ctx = stream_context_create($opts);
$res = file_get_contents($url, false, $ctx);
print_r(json_decode($res, true));

Postman Setup Guide

Get Postman ↗
  1. See official documentation for authentication and setup.

What can you build with Forem API V1?

Forem API V1 is a Social API. Developers commonly use social APIs for:

  • adding social login (Sign in with Google/Twitter)
  • fetching user-generated content for analysis
  • scheduling and publishing social posts
  • tracking mentions and engagement metrics
  • building community dashboards

No authentication required. This API is open — no signup or key needed. Ideal for quick prototypes and public-facing features. Forem API V1 is free to use, making it a low-risk choice to experiment with.

New to APIs? Read our beginner's guide · Learn about API keys · What is REST?

Open documentation ↗