{ "openapi": "3.0.3", "info": { "title": "Forem API V1", "version": "1.0.0", "description": "Access Forem articles, users and other resources via API.\n For a real-world example of Forem in action, check out [DEV](https://www.dev.to).\n All endpoints can be accessed with the 'api-key' header and a accept header, but\n some of them are accessible publicly without authentication.\n\n Dates and date times, unless otherwise specified, must be in\n the [RFC 3339](https://tools.ietf.org/html/rfc3339) format." }, "paths": { "/api/agent_sessions": { "get": { "summary": "list the authenticated user's agent sessions", "tags": [ "agent_sessions" ], "description": "This endpoint allows the client to list their own agent sessions.\n\nAgent sessions are coding conversation transcripts uploaded from CLI tools like\n[Claude Code](https://github.com/anthropics/claude-code). Use the\n[Forem CLI plugin](https://github.com/forem/forem-cli-plugin) to upload sessions\nfrom the command line.", "operationId": "getAgentSessions", "responses": { "200": { "description": "successful", "content": { "application/json": { "example": [ { "id": 40, "slug": "session-a-jsq3q8", "title": "Session A", "tool_name": "claude_code", "total_messages": 2, "published": false, "created_at": "2026-05-28T12:45:15-06:00", "updated_at": "2026-05-28T12:45:15-06:00", "url": "http://forem.test/agent_sessions/session-a-jsq3q8" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AgentSessionIndex" } } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } }, "post": { "summary": "upload a new agent session", "tags": [ "agent_sessions" ], "description": "This endpoint allows the client to create a new agent session.\n\nSessions are created from pre-parsed and curated data (`curated_data` JSON) and\noptionally linked to an S3-stored raw file via `s3_key`. Use the presign endpoint\nto get an upload URL for the raw file first.\n\nUse the [Forem CLI plugin](https://github.com/forem/forem-cli-plugin) to upload\nsessions directly from the command line.", "operationId": "createAgentSession", "parameters": [ ], "responses": { "201": { "description": "created", "content": { "application/json": { "example": { "id": 41, "slug": "my-claude-session-jg1xld", "title": "My Claude Session", "tool_name": "claude_code", "total_messages": 2, "published": false, "created_at": "2026-05-28T12:45:15-06:00", "url": "http://forem.test/agent_sessions/my-claude-session-jg1xld" }, "schema": { "$ref": "#/components/schemas/AgentSessionIndex" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "unprocessable", "content": { "application/json": { "example": { "error": "Missing session content. Provide 'curated_data' or 's3_key'.", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string", "description": "Title for the session (auto-generated if omitted)" }, "curated_data": { "type": "string", "description": "JSON string of curated session data with messages array and metadata." }, "s3_key": { "type": "string", "description": "S3 object key from presign endpoint (optional)." }, "tool_name": { "type": "string", "description": "Tool that produced the session (e.g. claude_code, codex).", "enum": [ "claude_code", "codex", "gemini_cli", "github_copilot", "opencode", "pi" ] } }, "required": [ "curated_data" ] } } } } } }, "/api/agent_sessions/{id}": { "get": { "summary": "show details for an agent session", "tags": [ "agent_sessions" ], "description": "This endpoint allows the client to retrieve a single agent session by slug or ID.\nReturns the full session including messages, curated selections, and slices.", "operationId": "getAgentSessionById", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The slug or ID of the agent session.", "schema": { "type": "string" }, "example": "my-session-abc123" } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 42, "slug": "my-session-15rjsb", "title": "My Session", "tool_name": "claude_code", "total_messages": 2, "curated_count": 2, "published": false, "metadata": { "tool_name": "claude_code", "total_messages": 2 }, "messages": [ { "role": "user", "index": 0, "content": [ { "text": "Hello", "type": "text" } ] }, { "role": "assistant", "index": 1, "content": [ { "text": "Hi there", "type": "text" } ] } ], "slices": [ ], "created_at": "2026-05-28T12:45:15-06:00", "updated_at": "2026-05-28T12:45:15-06:00", "url": "http://forem.test/agent_sessions/my-session-15rjsb" }, "schema": { "$ref": "#/components/schemas/AgentSessionShow" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/articles": { "post": { "summary": "Publish article", "tags": [ "articles" ], "description": "This endpoint allows the client to create a new article.\n\n\"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.", "operationId": "createArticle", "parameters": [ ], "responses": { "201": { "description": "An Article", "content": { "application/json": { "example": { "type_of": "article", "id": 2233, "title": "New article", "description": "New post example", "readable_publish_date": "May 28", "slug": "new-article-2gaj", "path": "/username8/new-article-2gaj", "url": "http://forem.test/username8/new-article-2gaj", "comments_count": 0, "public_reactions_count": 0, "collection_id": 13, "published_timestamp": "2026-05-28T18:45:16Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "social_image": "https://thepracticaldev.s3.amazonaws.com/i/5wfo25724gzgk5e5j50g.jpg", "canonical_url": "https://dev.to/fdocr/headless-chrome-dual-mode-tests-for-ruby-on-rails-4p6g", "created_at": "2026-05-28T18:45:16Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:16Z", "last_comment_at": "2026-05-28T18:45:16Z", "reading_time_minutes": 1, "tag_list": "", "tags": [ ], "body_html": "
New body for the article
\n\n", "body_markdown": "**New** body for the article", "user": { "name": "Delorse \"Duncan\" \\:/ Kerluke", "username": "username8", "twitter_username": "twitter8", "github_username": "github8", "user_id": 4056, "website_url": null, "profile_image": "/uploads/user/profile_image/4056/149b80c3-1a8e-4e1f-ac70-9da821c6eb8a.jpeg", "profile_image_90": "/uploads/user/profile_image/4056/149b80c3-1a8e-4e1f-ac70-9da821c6eb8a.jpeg" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: article", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Article" } } } } }, "get": { "summary": "Published articles", "security": [ ], "tags": [ "articles" ], "description": "This endpoint allows the client to retrieve a list of articles.\n\n\"Articles\" are all the posts that users create on DEV that typically\nshow up in the feed. They can be a blog post, a discussion question,\na help thread etc. but is referred to as article within the code.\n\nBy default it will return featured, published articles ordered\nby descending popularity.\n\nIt supports pagination, each page will contain `30` articles by default.", "operationId": "getArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "tag", "in": "query", "required": false, "description": "Using this parameter will retrieve articles that contain the requested tag. Articles\nwill be ordered by descending popularity.This parameter can be used in conjuction with `top`.", "schema": { "type": "string" }, "example": "discuss" }, { "name": "tags", "in": "query", "required": false, "description": "Using this parameter will retrieve articles with any of the comma-separated tags.\nArticles will be ordered by descending popularity.", "schema": { "type": "string" }, "example": "javascript, css" }, { "name": "tags_exclude", "in": "query", "required": false, "description": "Using this parameter will retrieve articles that do _not_ contain _any_\nof comma-separated tags. Articles will be ordered by descending popularity.", "schema": { "type": "string" }, "example": "node, java" }, { "name": "username", "in": "query", "required": false, "description": "Using this parameter will retrieve articles belonging\n to a User or Organization ordered by descending publication date.\n If `state=all` the number of items returned will be `1000` instead of the default `30`.\n This parameter can be used in conjuction with `state`.", "schema": { "type": "string" }, "example": "ben" }, { "name": "state", "in": "query", "required": false, "description": "Using this parameter will allow the client to check which articles are fresh or rising.\n If `state=fresh` the server will return fresh articles.\n If `state=rising` the server will return rising articles.\n This param can be used in conjuction with `username`, only if set to `all`.", "schema": { "type": "string", "enum": [ "fresh", "rising", "all" ] }, "example": "fresh" }, { "name": "top", "in": "query", "required": false, "description": "Using this parameter will allow the client to return the most popular articles\nin the last `N` days.\n`top` indicates the number of days since publication of the articles returned.\nThis param can be used in conjuction with `tag`.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 2 }, { "name": "collection_id", "in": "query", "required": false, "description": "Adding this will allow the client to return the list of articles\nbelonging to the requested collection, ordered by ascending publication date.", "schema": { "type": "integer", "format": "int32" }, "example": 99 } ], "responses": { "200": { "description": "A List of Articles", "content": { "application/json": { "example": [ { "type_of": "article", "id": 2236, "title": "The Golden Apples of the Sun4", "description": "Banh mi vegan fingerstache. Craft beer wes anderson portland you probably havent heard of them swag....", "readable_publish_date": "May 28", "slug": "the-golden-apples-of-the-sun4-453o", "path": "/username12/the-golden-apples-of-the-sun4-453o", "url": "http://forem.test/username12/the-golden-apples-of-the-sun4-453o", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:16Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/30-08b2d52669e0680784f50291966e33f77cbee815907e6abbacf74018fa3f3567.png", "social_image": "http://forem.test/assets/30-08b2d52669e0680784f50291966e33f77cbee815907e6abbacf74018fa3f3567.png", "canonical_url": "http://forem.test/username12/the-golden-apples-of-the-sun4-453o", "created_at": "2026-05-28T18:45:16Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:16Z", "last_comment_at": "2026-05-28T18:45:16Z", "reading_time_minutes": 1, "tag_list": [ "discuss" ], "tags": "discuss", "user": { "name": "Joan \"Stormy\" \\:/ Nienow", "username": "username12", "twitter_username": "twitter12", "github_username": "github12", "user_id": 4060, "website_url": null, "profile_image": "/uploads/user/profile_image/4060/aaa06fa2-d0f3-40cf-9578-bc53c1ca69e3.jpeg", "profile_image_90": "/uploads/user/profile_image/4060/aaa06fa2-d0f3-40cf-9578-bc53c1ca69e3.jpeg" }, "organization": { "name": "Bergnaum Inc", "username": "org4", "slug": "org4", "profile_image": "/uploads/organization/profile_image/560/319c0831-b2a0-4bc1-a40b-bd5fdae4ce68.png", "profile_image_90": "/uploads/organization/profile_image/560/319c0831-b2a0-4bc1-a40b-bd5fdae4ce68.png" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/latest": { "get": { "summary": "Published articles sorted by published date", "security": [ ], "tags": [ "articles" ], "description": "This endpoint allows the client to retrieve a list of articles. ordered by descending publish date.\n\nIt supports pagination, each page will contain 30 articles by default.", "operationId": "getLatestArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "200": { "description": "A List of Articles", "content": { "application/json": { "example": [ { "type_of": "article", "id": 2239, "title": "The Mirror Crackd from Side to Side7", "description": "Vhs aesthetic park freegan microdosing polaroid keytar squid. Hammock hella cardigan shoreditch...", "readable_publish_date": "May 28", "slug": "the-mirror-crackd-from-side-to-side7-98n", "path": "/username15/the-mirror-crackd-from-side-to-side7-98n", "url": "http://forem.test/username15/the-mirror-crackd-from-side-to-side7-98n", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:17Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/34-d27f3a4a9f6f1f373003c74b31749764691f510b2a18b55039478583864a067e.png", "social_image": "http://forem.test/assets/34-d27f3a4a9f6f1f373003c74b31749764691f510b2a18b55039478583864a067e.png", "canonical_url": "http://forem.test/username15/the-mirror-crackd-from-side-to-side7-98n", "created_at": "2026-05-28T18:45:17Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:17Z", "last_comment_at": "2026-05-28T18:45:17Z", "reading_time_minutes": 1, "tag_list": [ "javascript", "html", "discuss" ], "tags": "javascript, html, discuss", "user": { "name": "Evelina \"Norman\" \\:/ Moen", "username": "username15", "twitter_username": "twitter15", "github_username": "github15", "user_id": 4063, "website_url": null, "profile_image": "/uploads/user/profile_image/4063/194ffea0-3e45-440a-a97c-7b37da7fbf75.jpeg", "profile_image_90": "/uploads/user/profile_image/4063/194ffea0-3e45-440a-a97c-7b37da7fbf75.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } }, { "type_of": "article", "id": 2238, "title": "The Green Bay Tree6", "description": "Helvetica yr venmo xoxo direct trade meh. Forage polaroid etsy. Forage vhs fanny pack. Put a bird on...", "readable_publish_date": "May 28", "slug": "the-green-bay-tree6-4cif", "path": "/username14/the-green-bay-tree6-4cif", "url": "http://forem.test/username14/the-green-bay-tree6-4cif", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:16Z", "language": null, "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/22-837b6c737e37b6d229b36d73e95ead7f26e0a346e0aa7dfbca74630ae161fb0d.png", "social_image": "http://forem.test/assets/22-837b6c737e37b6d229b36d73e95ead7f26e0a346e0aa7dfbca74630ae161fb0d.png", "canonical_url": "http://forem.test/username14/the-green-bay-tree6-4cif", "created_at": "2026-05-28T18:45:16Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:16Z", "last_comment_at": "2026-05-28T18:45:16Z", "reading_time_minutes": 1, "tag_list": [ "javascript", "html", "discuss" ], "tags": "javascript, html, discuss", "user": { "name": "Aletha \"Jordon\" \\:/ Lubowitz", "username": "username14", "twitter_username": "twitter14", "github_username": "github14", "user_id": 4062, "website_url": null, "profile_image": "/uploads/user/profile_image/4062/b1e0cad0-d46f-4386-9e32-28318fc4e6e9.jpeg", "profile_image_90": "/uploads/user/profile_image/4062/b1e0cad0-d46f-4386-9e32-28318fc4e6e9.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } }, { "type_of": "article", "id": 2237, "title": "His Dark Materials5", "description": "Kitsch pitchfork schlitz 90s. Everyday wes anderson flannel offal muggle magic biodiesel try-hard...", "readable_publish_date": "May 28", "slug": "his-dark-materials5-52pe", "path": "/username13/his-dark-materials5-52pe", "url": "http://forem.test/username13/his-dark-materials5-52pe", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:16Z", "language": null, "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/40-57aabe055a9fc60491e0fca9a4dade362141764e7ad214956bbfc9c9e69763b0.png", "social_image": "http://forem.test/assets/40-57aabe055a9fc60491e0fca9a4dade362141764e7ad214956bbfc9c9e69763b0.png", "canonical_url": "http://forem.test/username13/his-dark-materials5-52pe", "created_at": "2026-05-28T18:45:16Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:16Z", "last_comment_at": "2026-05-28T18:45:16Z", "reading_time_minutes": 1, "tag_list": [ "javascript", "html", "discuss" ], "tags": "javascript, html, discuss", "user": { "name": "Clinton \"Timika\" \\:/ Konopelski", "username": "username13", "twitter_username": "twitter13", "github_username": "github13", "user_id": 4061, "website_url": null, "profile_image": "/uploads/user/profile_image/4061/b1948bf9-f870-463c-a72d-649a017353b4.jpeg", "profile_image_90": "/uploads/user/profile_image/4061/b1948bf9-f870-463c-a72d-649a017353b4.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/{id}": { "get": { "summary": "Published article by id", "security": [ ], "tags": [ "articles" ], "description": "This endpoint allows the client to retrieve a single published article given its `id`.", "operationId": "getArticleById", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "An Article", "content": { "application/json": { "example": { "type_of": "article", "id": 2240, "title": "Blue Remembered Earth8", "description": "Yolo next level green juice banjo flexitarian photo booth. Chillwave ennui kogi. Thundercats...", "readable_publish_date": "May 28", "slug": "blue-remembered-earth8-3dmj", "path": "/username16/blue-remembered-earth8-3dmj", "url": "http://forem.test/username16/blue-remembered-earth8-3dmj", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:17Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/12-f9d673ae4ff98002f782ab82c641f2f26673be728e8f5409bea83f2d1de15323.png", "social_image": "http://forem.test/assets/12-f9d673ae4ff98002f782ab82c641f2f26673be728e8f5409bea83f2d1de15323.png", "canonical_url": "http://forem.test/username16/blue-remembered-earth8-3dmj", "created_at": "2026-05-28T18:45:17Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:17Z", "last_comment_at": "2026-05-28T18:45:17Z", "reading_time_minutes": 1, "tag_list": "discuss", "tags": [ "discuss" ], "body_html": "Yolo next level green juice banjo flexitarian photo booth. Chillwave ennui kogi. Thundercats intelligentsia tousled typewriter flexitarian.
\n\nBefore they sold out squid pbrb waistcoat.
\n\n", "body_markdown": "---\ntitle: Blue Remembered Earth8\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nYolo next level green juice banjo flexitarian photo booth. Chillwave ennui kogi. Thundercats intelligentsia tousled typewriter flexitarian.\n\n\nBefore they sold out squid pbrb waistcoat.\n\n", "user": { "name": "Vance \"Larry\" \\:/ Nikolaus", "username": "username16", "twitter_username": "twitter16", "github_username": "github16", "user_id": 4064, "website_url": null, "profile_image": "/uploads/user/profile_image/4064/17fa7924-534e-4da2-8dc3-5de871a9e38e.jpeg", "profile_image_90": "/uploads/user/profile_image/4064/17fa7924-534e-4da2-8dc3-5de871a9e38e.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } }, "404": { "description": "Article Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "put": { "summary": "Update an article by id", "tags": [ "articles" ], "description": "This endpoint allows the client to update an existing article.\n\n\"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.", "operationId": "updateArticle", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to unpublish.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 123 } ], "responses": { "200": { "description": "An Article", "content": { "application/json": { "example": { "type_of": "article", "id": 2241, "title": "The Heart Is a Lonely Hunter9", "description": "Scenester banh mi truffaut. Helvetica keytar chillwave tote bag mixtape forage intelligentsia carry....", "readable_publish_date": "May 28", "slug": "the-heart-is-a-lonely-hunter9-2ip2", "path": "/username17/the-heart-is-a-lonely-hunter9-2ip2", "url": "http://forem.test/username17/the-heart-is-a-lonely-hunter9-2ip2", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:17Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/23-33ea5a2b5af3dc15b9ed90de0b850f67e2390eaec3361d6687d3b9750c699f84.png", "social_image": "http://forem.test/assets/23-33ea5a2b5af3dc15b9ed90de0b850f67e2390eaec3361d6687d3b9750c699f84.png", "canonical_url": "http://forem.test/username17/the-heart-is-a-lonely-hunter9-2ip2", "created_at": "2026-05-28T18:45:17Z", "edited_at": "2026-05-28T18:45:17Z", "crossposted_at": null, "published_at": "2026-05-28T18:45:17Z", "last_comment_at": "2026-05-28T18:45:17Z", "reading_time_minutes": 1, "tag_list": "discuss", "tags": [ "discuss" ], "body_html": "New body for the article
\n\n", "body_markdown": "**New** body for the article", "user": { "name": "Celsa \"Edwardo\" \\:/ Kirlin", "username": "username17", "twitter_username": "twitter17", "github_username": "github17", "user_id": 4065, "website_url": null, "profile_image": "/uploads/user/profile_image/4065/36a7e5c8-ce49-410d-8fc0-7c2b776c8d4f.jpeg", "profile_image_90": "/uploads/user/profile_image/4065/36a7e5c8-ce49-410d-8fc0-7c2b776c8d4f.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } } } } }, "404": { "description": "Article Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: article", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Article" } } } } } }, "/api/articles/{username}/{slug}": { "get": { "summary": "Published article by path", "security": [ ], "tags": [ "articles" ], "description": "This endpoint allows the client to retrieve a single published article given its `path`.", "operationId": "getArticleByPath", "parameters": [ { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "An Article", "content": { "application/json": { "example": { "type_of": "article", "id": 2244, "title": "Of Human Bondage12", "description": "Vinegar bespoke mumblecore polaroid. Portland 3 wolf moon yolo austin scenester meditation artisan...", "readable_publish_date": "May 28", "slug": "of-human-bondage12-4bfh", "path": "/username21/of-human-bondage12-4bfh", "url": "http://forem.test/username21/of-human-bondage12-4bfh", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:17Z", "language": null, "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", "social_image": "http://forem.test/assets/20-92231c1d2ddb3b707b8c1b5cb711ef17632ff2a64495970a58518ce33c3a4f76.png", "canonical_url": "http://forem.test/username21/of-human-bondage12-4bfh", "created_at": "2026-05-28T18:45:17Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:17Z", "last_comment_at": "2026-05-28T18:45:17Z", "reading_time_minutes": 1, "tag_list": "discuss", "tags": [ "discuss" ], "body_html": "Vinegar bespoke mumblecore polaroid. Portland 3 wolf moon yolo austin scenester meditation artisan pbrb.
\n\nMeggings master yolo cliche. Pop-up put a bird on it poutine single-origin coffee brunch.
\n\n", "body_markdown": "---\ntitle: Of Human Bondage12\npublished: true\ntags: discuss\ndate: \nseries: \ncanonical_url: \n\n---\n\nVinegar bespoke mumblecore polaroid. Portland 3 wolf moon yolo austin scenester meditation artisan pbrb.\n\n\nMeggings master yolo cliche. Pop-up put a bird on it poutine single-origin coffee brunch.\n\n", "user": { "name": "Joaquin \"Tayna\" \\:/ Veum", "username": "username21", "twitter_username": "twitter21", "github_username": "github21", "user_id": 4069, "website_url": null, "profile_image": "/uploads/user/profile_image/4069/cd9be7fb-4277-4e90-9351-de7a241d1856.jpeg", "profile_image_90": "/uploads/user/profile_image/4069/cd9be7fb-4277-4e90-9351-de7a241d1856.jpeg" }, "flare_tag": { "name": "discuss", "bg_color_hex": "#000000", "text_color_hex": "#ffffff" } }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } }, "404": { "description": "Article Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/articles/me": { "get": { "summary": "User's articles", "tags": [ "articles", "users" ], "description": "This endpoint allows the client to retrieve a list of published articles on behalf of an authenticated user.\n\n\"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.\n\nPublished articles will be in reverse chronological publication order.\n\nIt will return published articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A List of the authenticated user's Articles", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/me/published": { "get": { "summary": "User's published articles", "tags": [ "articles", "users" ], "description": "This endpoint allows the client to retrieve a list of published articles on behalf of an authenticated user.\n\n\"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.\n\nPublished articles will be in reverse chronological publication order.\n\nIt will return published articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserPublishedArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A List of the authenticated user's Articles", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/me/unpublished": { "get": { "summary": "User's unpublished articles", "tags": [ "articles", "users" ], "description": "This endpoint allows the client to retrieve a list of unpublished articles on behalf of an authenticated user.\n\n\"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.\n\nUnpublished articles will be in reverse chronological creation order.\n\nIt will return unpublished articles with pagination. By default a page will contain 30 articles.", "operationId": "getUserUnpublishedArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A List of the authenticated user's Articles", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/me/all": { "get": { "summary": "User's all articles", "tags": [ "articles", "users" ], "description": "This endpoint allows the client to retrieve a list of all articles on behalf of an authenticated user.\n\n\"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.\n\nIt will return both published and unpublished articles with pagination.\n\nUnpublished articles will be at the top of the list in reverse chronological creation order. Published articles will follow in reverse chronological publication order.\n\nBy default a page will contain 30 articles.", "operationId": "getUserAllArticles", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A List of the authenticated user's Articles", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/articles/{id}/unpublish": { "put": { "summary": "Unpublish an article", "tags": [ "articles" ], "description": "This endpoint allows the client to unpublish an article.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThe article will be unpublished and will no longer be visible to the public. It will remain\nin the database and will set back to draft status on the author's posts dashboard. Any\nnotifications associated with the article will be deleted. Any comments on the article\nwill remain.", "operationId": "unpublishArticle", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the article to unpublish.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 }, { "name": "note", "in": "query", "required": false, "description": "Content for the note that's created along with unpublishing", "schema": { "type": "string" }, "example": "Admin requested unpublishing all articles via API" } ], "responses": { "204": { "description": "Article successfully unpublished" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Article Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/segments": { "get": { "summary": "Manually managed audience segments", "tags": [ "segments" ], "description": "This endpoint allows the client to retrieve a list of audience segments.\n\nAn audience segment is a group of users that can be targeted by a Billboard. This API only permits managing segments you create and maintain yourself.\n\nThe endpoint supports pagination, and each page will contain `30` segments by default.", "operationId": "getSegments", "parameters": [ { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "200": { "description": "A List of manually managed audience segments", "content": { "application/json": { "example": [ { "id": 34, "created_at": "2026-05-28T12:45:19.104-06:00", "name": null, "type_of": "manual", "updated_at": "2026-05-28T12:45:19.104-06:00", "user_count": 1 }, { "id": 33, "created_at": "2026-05-28T12:45:19.016-06:00", "name": null, "type_of": "manual", "updated_at": "2026-05-28T12:45:19.016-06:00", "user_count": 3 } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Segment" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } }, "post": { "summary": "Create a manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to create a new audience segment.\n\nAn audience segment is a group of users that can be targeted by a Billboard. This API only permits managing segments you create and maintain yourself.", "operationId": "createSegment", "responses": { "201": { "description": "A manually managed audience segment", "content": { "application/json": { "example": { "id": 35, "created_at": "2026-05-28T12:45:19.421-06:00", "name": null, "type_of": "manual", "updated_at": "2026-05-28T12:45:19.421-06:00" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/segments/{id}": { "get": { "summary": "A manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to retrieve a single manually-managed audience segment specified by ID.", "operationId": "getSegment", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 1 } } ], "responses": { "200": { "description": "The audience segment", "content": { "application/json": { "example": { "id": 36, "created_at": "2026-05-28T12:45:19.625-06:00", "name": null, "type_of": "manual", "updated_at": "2026-05-28T12:45:19.625-06:00", "user_count": 3 }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Segment" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Audience Segment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "delete": { "summary": "Delete a manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to delete an audience segment specified by ID.\n\nAudience segments cannot be deleted if there are still any Billboards using them.", "operationId": "deleteSegment", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 1 } } ], "responses": { "200": { "description": "The deleted audience segment", "content": { "application/json": { "example": { "id": 40, "created_at": "2026-05-28T12:45:20.004-06:00", "name": null, "type_of": "manual", "updated_at": "2026-05-28T12:45:20.004-06:00" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Audience Segment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "409": { "description": "Audience segment could not be deleted", "content": { "application/json": { "example": { "error": "Segments cannot be deleted while in use by any billboards" } } } } } } }, "/api/segments/{id}/users": { "get": { "summary": "Users in a manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to retrieve a list of the users in an audience segment specified by ID. The endpoint supports pagination, and each page will contain `30` users by default.", "operationId": "getUsersInSegment", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 1 } }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "200": { "description": "A List of users in the audience segment", "content": { "application/json": { "example": [ { "type_of": "user", "id": 4109, "username": "username61", "name": "Erminia \"Pedro\" \\:/ Turcotte", "twitter_username": "twitter61", "github_username": "github61", "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4109/6812d241-6f58-4837-885e-56a5c1a1cac7.jpeg" }, { "type_of": "user", "id": 4110, "username": "username62", "name": "Perry \"Jazmin\" \\:/ Harvey", "twitter_username": "twitter62", "github_username": "github62", "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4110/66331066-af5b-44d8-bf8c-5a3787ecbfa2.jpeg" }, { "type_of": "user", "id": 4111, "username": "username63", "name": "Kristofer \"Ruth\" \\:/ Graham", "twitter_username": "twitter63", "github_username": "github63", "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4111/1536d24e-ea86-4abf-bbac-d0eef3b4ebbd.jpeg" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/User" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Audience Segment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/segments/{id}/add_users": { "put": { "summary": "Add users to a manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to add users in bulk to an audience segment specified by ID.\n\nSuccesses are users that were included in the segment (even if they were already in it), and failures are users that could not be added to the segment.", "operationId": "addUsersToSegment", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 1 } } ], "responses": { "200": { "description": "Result of adding the users to the segment.", "content": { "application/json": { "example": { "succeeded": [ 4117, 4118, 4119 ], "failed": [ ] } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Audience Segment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: user_ids", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SegmentUserIds" } } } } } }, "/api/segments/{id}/remove_users": { "put": { "summary": "Remove users from a manually managed audience segment", "tags": [ "segments" ], "description": "This endpoint allows the client to remove users in bulk from an audience segment specified by ID.\n\nSuccesses are users that were removed; failures are users that weren't a part of the segment.", "operationId": "removeUsersFromSegment", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 1 } } ], "responses": { "200": { "description": "Result of removing the users to the segment.", "content": { "application/json": { "example": { "succeeded": [ 4136, 4137, 4138 ], "failed": [ ] } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Audience Segment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: user_ids", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SegmentUserIds" } } } } } }, "/api/billboards": { "get": { "summary": "Billboards", "tags": [ "billboards" ], "description": "This endpoint allows the client to retrieve a list of all billboards.", "responses": { "200": { "description": "successful", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Billboard" } } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } }, "post": { "summary": "Create a billboard", "tags": [ "billboards" ], "description": "This endpoint allows the client to create a new billboard.", "parameters": [ ], "responses": { "201": { "description": "A billboard", "content": { "application/json": { "example": { "id": 100, "approved": true, "audience_segment_id": null, "body_markdown": "# Hi, this is ad\nYep, it's an ad", "browser_context": "all_browsers", "cached_tag_list": "", "clicks_count": 0, "color": null, "content_updated_at": "2026-05-28T12:45:22.793-06:00", "counts_tabulated_at": null, "created_at": "2026-05-28T12:45:22.793-06:00", "creator_id": null, "custom_display_label": null, "dismissal_sku": null, "display_to": "all", "event_id": null, "exclude_article_ids": "", "exclude_role_names": [ ], "exclude_survey_completions": false, "exclude_survey_ids": "", "expires_at": null, "impressions_count": 0, "include_subforem_ids": [ ], "name": "Example Billboard", "organization_id": null, "page_id": null, "placement_area": "post_comments", "prefer_paired_with_billboard_id": null, "preferred_article_ids": [ ], "priority": false, "processed_html": "Yep, it's an ad
", "published": true, "render_mode": "forem_markdown", "requires_cookies": false, "special_behavior": "nothing", "success_rate": 0.0, "tags_array": [ ], "target_role_names": [ ], "template": "authorship_box", "type_of": "in_house", "updated_at": "2026-05-28T12:45:22.793-06:00", "weight": 1.0, "audience_segment_type": null, "tag_list": "", "target_geolocations": [ "US-WA", "CA-BC" ] }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Billboard" } } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "unprocessable", "content": { "application/json": { "example": { "error": "Validation failed: Placement area is not included in the list", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Billboard" } } } } } } }, "/api/billboards/{id}": { "get": { "summary": "A billboard (by id)", "tags": [ "billboards" ], "description": "This endpoint allows the client to retrieve a single billboard, via its id.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the billboard.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 123 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 101, "approved": false, "audience_segment_id": null, "body_markdown": "Hello _hey_ Hey hey 2", "browser_context": "all_browsers", "cached_tag_list": "", "clicks_count": 0, "color": null, "content_updated_at": "2026-05-28T12:45:22.996-06:00", "counts_tabulated_at": null, "created_at": "2026-05-28T12:45:22.992-06:00", "creator_id": null, "custom_display_label": null, "dismissal_sku": null, "display_to": "all", "event_id": null, "exclude_article_ids": "", "exclude_role_names": [ ], "exclude_survey_completions": false, "exclude_survey_ids": "", "expires_at": null, "impressions_count": 0, "include_subforem_ids": [ ], "name": "Billboard 101", "organization_id": 562, "page_id": null, "placement_area": "sidebar_left", "prefer_paired_with_billboard_id": null, "preferred_article_ids": [ ], "priority": false, "processed_html": "Hello hey Hey hey 2
", "published": false, "render_mode": "forem_markdown", "requires_cookies": false, "special_behavior": "nothing", "success_rate": 0.0, "tags_array": [ ], "target_role_names": [ ], "template": "authorship_box", "type_of": "in_house", "updated_at": "2026-05-28T12:45:22.996-06:00", "weight": 1.0, "audience_segment_type": null, "tag_list": "", "target_geolocations": [ ] } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown Billboard ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "put": { "summary": "Update a billboard by ID", "tags": [ "billboards" ], "description": "This endpoint allows the client to update the attributes of a single billboard, via its id.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the billboard.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 123 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "approved": false, "body_markdown": "Hello _hey_ Hey hey 3", "creator_id": null, "display_to": "all", "page_id": null, "browser_context": "all_browsers", "name": "Billboard 102", "organization_id": 563, "placement_area": "sidebar_left", "published": false, "dismissal_sku": null, "type_of": "in_house", "exclude_article_ids": "", "weight": 1.0, "requires_cookies": false, "color": null, "audience_segment_id": null, "priority": false, "special_behavior": "nothing", "custom_display_label": null, "template": "authorship_box", "render_mode": "forem_markdown", "prefer_paired_with_billboard_id": null, "expires_at": null, "exclude_survey_completions": false, "exclude_survey_ids": "", "cached_tag_list": "", "id": 102, "clicks_count": 0, "content_updated_at": "2026-05-28T12:45:23.227-06:00", "counts_tabulated_at": null, "created_at": "2026-05-28T12:45:23.224-06:00", "event_id": null, "exclude_role_names": [ ], "impressions_count": 0, "include_subforem_ids": [ ], "preferred_article_ids": [ ], "processed_html": "Hello hey Hey hey 3
", "success_rate": 0.0, "tags_array": [ ], "target_role_names": [ ], "updated_at": "2026-05-28T12:45:23.227-06:00", "audience_segment_type": null, "tag_list": "", "target_geolocations": [ ] }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Billboard" } } } } }, "404": { "description": "not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Billboard" } } } } } } }, "/api/billboards/{id}/unpublish": { "put": { "summary": "Unpublish a billboard", "tags": [ "billboards" ], "description": "This endpoint allows the client to remove a billboard from rotation by un-publishing it.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the billboard to unpublish.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 123 } ], "responses": { "204": { "description": "no content" }, "404": { "description": "not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/comments": { "get": { "summary": "Comments", "security": [ ], "tags": [ "comments" ], "description": "This endpoint allows the client to retrieve all comments belonging to an article or podcast episode as threaded conversations.\n\nIt will return the all top level comments with their nested comments as threads. See the format specification for further details.\n\nIt supports pagination, each page will contain `50` top level comments (and as many child comments they have) by default.\n\nIf the page parameter is not passed, all comments of an article or podcast will be returned.\n", "operationId": "getCommentsByArticleId", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "a_id", "in": "query", "required": false, "description": "Article identifier.", "schema": { "type": "string" }, "example": "321" }, { "name": "p_id", "in": "query", "required": false, "description": "Podcast Episode identifier.", "schema": { "type": "string" }, "example": "321" }, { "name": "page", "in": "query", "required": false, "description": "Page", "schema": { "type": "string" }, "example": "321" } ], "responses": { "200": { "description": "A List of Comments", "content": { "application/json": { "example": [ { "type_of": "comment", "id_code": "9e", "created_at": "2026-05-28T18:45:23Z", "body_html": "Cronut direct trade thundercats. Sustainable ethical asymmetrical +1 pop-up flexitarian scenester. Pitchfork yuccie cronut kale chips austin health.
\n\n", "user": { "name": "Kayleen \"Silvana\" \\:/ Hoppe", "username": "username127", "twitter_username": "twitter127", "github_username": "github127", "user_id": 4175, "website_url": null, "profile_image": "/uploads/user/profile_image/4175/3f3a1ddd-ab70-45f5-8600-f4e42a293990.jpeg", "profile_image_90": "/uploads/user/profile_image/4175/3f3a1ddd-ab70-45f5-8600-f4e42a293990.jpeg" }, "children": [ ] } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } } } } }, "404": { "description": "Resource Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/comments/{id}": { "get": { "summary": "Comment by id", "security": [ ], "tags": [ "comments" ], "description": "This endpoint allows the client to retrieve a comment as well as his descendants comments.\n\n It will return the required comment (the root) with its nested descendants as a thread.\n\n See the format specification for further details.", "operationId": "getCommentById", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Comment identifier.", "schema": { "type": "integer" }, "example": "321" } ], "responses": { "200": { "description": "A List of the Comments", "content": { "application/json": { "example": { "type_of": "comment", "id_code": "9g", "created_at": "2026-05-28T18:45:24Z", "body_html": "Single-origin coffee tofu schlitz typewriter hashtag ennui pork belly. Roof literally gluten-free retro paleo dreamcatcher skateboard twee.
\n\n", "user": { "name": "Melodie \"Darla\" \\:/ Rice", "username": "username131", "twitter_username": "twitter131", "github_username": "github131", "user_id": 4179, "website_url": null, "profile_image": "/uploads/user/profile_image/4179/3971613f-4374-4827-981c-82d413278b46.jpeg", "profile_image_90": "/uploads/user/profile_image/4179/3971613f-4374-4827-981c-82d413278b46.jpeg" }, "children": [ ] } } } }, "404": { "description": "Comment Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/follows/tags": { "get": { "summary": "Followed Tags", "tags": [ "followed_tags", "tags" ], "description": "This endpoint allows the client to retrieve a list of the tags they follow.", "operationId": "getFollowedTags", "responses": { "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A List of followed tags", "content": { "application/json": { "example": [ { "id": 2315, "name": "tag3", "points": 1.0 }, { "id": 2316, "name": "tag4", "points": 1.0 } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FollowedTag" } } } } } } } }, "/api/followers/users": { "get": { "summary": "Followers", "tags": [ "followers" ], "description": "This endpoint allows the client to retrieve a list of the followers they have.\n \"Followers\" are users that are following other users on the website.\n It supports pagination, each page will contain 80 followers by default.", "operationId": "getFollowers", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "sort", "in": "query", "required": false, "description": "Default is 'created_at'. Specifies the sort order for the created_at param of the follow\n relationship. To sort by newest followers first (descending order) specify\n ?sort=-created_at.", "schema": { "type": "string" }, "example": "created_at" } ], "responses": { "200": { "description": "A List of followers", "content": { "application/json": { "example": [ { "type_of": "user_follower", "id": 91, "created_at": "2026-05-28T18:45:24Z", "user_id": 4186, "name": "Duane \"Douglass\" \\:/ Muller", "path": "/username138", "username": "username138", "profile_image": "/uploads/user/profile_image/4186/c74aadc6-5b29-4f73-b23b-6908a8e9f105.jpeg" }, { "type_of": "user_follower", "id": 90, "created_at": "2026-05-28T18:45:24Z", "user_id": 4184, "name": "Nicki \"Alysa\" \\:/ Heathcote", "path": "/username136", "username": "username136", "profile_image": "/uploads/user/profile_image/4184/5d771299-1520-4435-8380-e9a7697c7c8c.jpeg" } ], "schema": { "type": "array", "items": { "description": "A follower", "type": "object", "properties": { "type_of": { "description": "user_follower by default", "type": "string" }, "id": { "type": "integer", "format": "int32" }, "user_id": { "description": "The follower's user id", "type": "integer", "format": "int32" }, "name": { "description": "The follower's name", "type": "string" }, "path": { "description": "A path to the follower's profile", "type": "string" }, "profile_image": { "description": "Profile image (640x640)", "type": "string" } } } } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/organizations/{username}": { "get": { "summary": "An organization (by username)", "tags": [ "organizations" ], "security": [ ], "description": "This endpoint allows the client to retrieve a single organization by their username", "operationId": "getOrganization", "parameters": [ { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "An Organization", "content": { "application/json": { "example": { "type_of": "organization", "id": 568, "username": "org12", "name": "Bartoletti-Dicki", "summary": "Tattooed gastropub cleanse tofu small batch franzen farm-to-table retro. Flannel whatever mustache hella pug shabby chic master.", "twitter_username": "org4787", "github_username": "org1607", "url": "http://torp.test/zack_sauer", "location": null, "tech_stack": null, "tag_line": null, "story": null, "joined_at": "2026-05-28T18:45:24Z", "profile_image": "/uploads/organization/profile_image/568/37584a82-a0bf-41f8-9807-871b71df211c.png" }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Organization" } } } } }, "404": { "description": "Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/organizations/{organization_id_or_username}/users": { "get": { "summary": "Organization's users", "tags": [ "organizations", "users" ], "security": [ ], "description": "This endpoint allows the client to retrieve a list of users belonging to the organization\n\nIt supports pagination, each page will contain `30` users by default.", "operationId": "getOrgUsers", "parameters": [ { "name": "organization_id_or_username", "in": "path", "required": true, "schema": { "type": "string" } }, { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "200": { "description": "An Organization's users (with ID)", "content": { "application/json": { "example": [ { "type_of": "user", "id": 4199, "username": "username151", "name": "Maria \"Mario\" \\:/ Pfeffer", "twitter_username": "twitter151", "github_username": "github151", "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4199/a36085cc-b1c4-4228-a351-a650ba7f4d44.jpeg" }, { "type_of": "user", "id": 4200, "username": "username152", "name": "Tiara \"Ebony\" \\:/ Watsica", "twitter_username": "twitter152", "github_username": "github152", "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4200/48796775-4796-4190-ae77-5eb3d3819e6d.jpeg" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/User" } } } } }, "404": { "description": "Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/organizations/{organization_id_or_username}/articles": { "get": { "summary": "Organization's Articles", "tags": [ "organizations", "articles" ], "security": [ ], "description": "This endpoint allows the client to retrieve a list of Articles belonging to the organization\n\nIt supports pagination, each page will contain `30` users by default.", "operationId": "getOrgArticles", "parameters": [ { "name": "organization_id_or_username", "in": "path", "required": true, "schema": { "type": "string" } }, { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "200": { "description": "An Organization's Articles (with ID)", "content": { "application/json": { "example": [ { "type_of": "article", "id": 2258, "title": "Whats Become of Waring26", "description": "Intelligentsia wes anderson pitchfork. Ramps single-origin coffee park kombucha vhs thundercats....", "readable_publish_date": "May 28", "slug": "whats-become-of-waring26-1010", "path": "/org18/whats-become-of-waring26-1010", "url": "http://forem.test/org18/whats-become-of-waring26-1010", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:25Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/38-3b0c46cc0d5367229799d282c99b2c42f33501201cac1ceb5c643f9ee11f06c6.png", "social_image": "http://forem.test/assets/38-3b0c46cc0d5367229799d282c99b2c42f33501201cac1ceb5c643f9ee11f06c6.png", "canonical_url": "http://forem.test/org18/whats-become-of-waring26-1010", "created_at": "2026-05-28T18:45:25Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:25Z", "last_comment_at": "2026-05-28T18:45:25Z", "reading_time_minutes": 1, "tag_list": [ "javascript", "html", "discuss" ], "tags": "javascript, html, discuss", "user": { "name": "Jeremy \"Arlena\" \\:/ Hintz", "username": "username162", "twitter_username": "twitter162", "github_username": "github162", "user_id": 4210, "website_url": null, "profile_image": "/uploads/user/profile_image/4210/cd03365d-5604-4d37-a2e1-62a537710192.jpeg", "profile_image_90": "/uploads/user/profile_image/4210/cd03365d-5604-4d37-a2e1-62a537710192.jpeg" }, "organization": { "name": "Marquardt-Von", "username": "org18", "slug": "org18", "profile_image": "/uploads/organization/profile_image/574/a6c694a7-f32f-45cc-974f-5aa18eca3eac.png", "profile_image_90": "/uploads/organization/profile_image/574/a6c694a7-f32f-45cc-974f-5aa18eca3eac.png" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } }, "404": { "description": "Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/organizations": { "get": { "summary": "Organizations", "tags": [ "organizations" ], "security": [ ], "description": "This endpoint allows the client to retrieve a list of Dev organizations.\n\n It supports pagination, each page will contain 10 tags by default.", "operationId": "getOrganizations", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam10to1000" } ], "responses": { "200": { "description": "A list of all organizations", "content": { "application/json": { "example": [ { "id": 576, "name": "Kuphal Inc", "profile_image": { "url": "/uploads/organization/profile_image/576/0c9dc328-e6c9-4dba-af45-700d5196da17.png" }, "slug": "org20", "summary": "Keffiyeh synth hashtag cold-pressed stumptown readymade. Microdosing drinking semiotics salvia gluten-free synth slow-carb tousled. Try-hard selvage ha", "tag_line": null, "url": "http://sipes.test/janiece_greenholt" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Organization" } } } } } } }, "post": { "summary": "Create an Organization", "tags": [ "organizations" ], "description": "This endpoint allows the client to create an organization with the provided parameters.\n It requires a token from a user with `admin` privileges.", "operationId": "createOrganization", "parameters": [ ], "responses": { "201": { "description": "Successful", "content": { "application/json": { "example": { "id": 579, "name": "New Test Org", "profile_image": "uploads/organization/profile_image/1/400x400.jpg", "slug": "org10001", "summary": "a newly created test org", "tag_line": "a test org's tagline", "url": "https://testorg.io" } } } }, "401": { "description": "Unauthorized" }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "Validation failed: Name can't be blank, Profile image can't be blank, Slug can't be blank", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Organization" } } } } } }, "/api/organizations/{id}": { "get": { "summary": "An organization (by id)", "tags": [ "organizations" ], "security": [ ], "description": "This endpoint allows the client to retrieve a single organization by their id", "operationId": "getOrganizationById", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "An Organization", "content": { "application/json": { "example": { "type_of": "organization", "id": 577, "username": "org21", "name": "Emmerich, Schamberger and Hand", "summary": "Keffiyeh tote bag craft beer. Park jean shorts helvetica butcher.", "twitter_username": "org8161", "github_username": "org5019", "url": "http://sanford-hintz.test/jose", "location": null, "tech_stack": null, "tag_line": null, "story": null, "joined_at": "2026-05-28T18:45:26Z", "profile_image": "/uploads/organization/profile_image/577/4516eda0-ba9a-43f5-80d0-bae770795069.png" }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Organization" } } } } }, "404": { "description": "Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "put": { "summary": "Update an organization by id", "tags": [ "organizations" ], "description": "This endpoint allows the client to update an existing organization.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the organization to update.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 123 } ], "responses": { "200": { "description": "An Organization", "content": { "application/json": { "example": { "id": 580, "name": "Mosciski, Moore and Moen", "profile_image": "/uploads/organization/profile_image/580/7cb3619e-86f9-465a-b7af-588b0f007fd1.png", "slug": "org23", "summary": "An updated summary for the organization.", "tag_line": null, "url": "http://will.example/lenita_gleason" } } } }, "404": { "description": "organization Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: organization", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Organization" } } } } }, "delete": { "summary": "Delete an Organization by id", "tags": [ "organizations" ], "description": "This endpoint allows the client to delete a single organization, specified by id", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the organization.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "message": "deletion scheduled for organization with ID 584", "status": 200 } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/pages": { "get": { "summary": "show details for all pages", "security": [ ], "tags": [ "pages" ], "description": "This endpoint allows the client to retrieve details for all Page objects.", "responses": { "200": { "description": "successful", "content": { "application/json": { "example": [ { "id": 47, "title": "Death Be Not Proud", "slug": "satisfaction-design", "description": "Quasi nesciunt dicta molestiae.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "Quaerat dolorem velit qui.", "processed_html": "Quaerat dolorem velit qui.
\n\n", "social_image": { "url": null }, "template": "contained", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Page" } } } } } } }, "post": { "summary": "pages", "tags": [ "pages" ], "description": "This endpoint allows the client to create a new page.", "parameters": [ ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 49, "title": "Example Page", "slug": "example1", "description": "a new page", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "# Hi, this is a New Page\nYep, it's an a new page", "processed_html": "Yep, it's an a new page
\n\n", "social_image": { "url": null }, "template": "contained", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "unprocessable", "content": { "application/json": { "example": { "id": null, "title": "Example Page", "slug": "example1", "description": "a new page", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "# Hi, this is a New Page\nYep, it's an a new page", "processed_html": null, "social_image": { "url": null }, "template": "moon", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null } } } } }, "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string", "description": "Title of the page" }, "slug": { "type": "string", "description": "Used to link to this page in URLs, must be unique and URL-safe" }, "description": { "type": "string", "description": "For internal use, helps similar pages from one another" }, "body_markdown": { "type": "string", "description": "The text (in markdown) of the ad (required)" }, "body_json": { "type": "string", "description": "For JSON pages, the JSON body" }, "is_top_level_path": { "type": "boolean", "description": "If true, the page is available at '/{slug}' instead of '/page/{slug}', use with caution" }, "template": { "type": "string", "enum": [ "contained", "full_within_layout", "nav_bar_included", "json", "css", "txt" ], "default": "contained", "description": "Controls what kind of layout the page is rendered in" } } } } } } } }, "/api/pages/{id}": { "get": { "summary": "show details for a page", "security": [ ], "tags": [ "pages" ], "description": "This endpoint allows the client to retrieve details for a single Page object, specified by ID.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the page.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 52, "title": "I Will Fear No Evil", "slug": "agree_strict", "description": "At qui et illum.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "Aut quia eaque sapiente.", "processed_html": "Aut quia eaque sapiente.
\n\n", "social_image": { "url": null }, "template": "contained", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null }, "schema": { "$ref": "#/components/schemas/Page" } } } } } }, "put": { "summary": "update details for a page", "tags": [ "pages" ], "description": "This endpoint allows the client to retrieve details for a single Page object, specified by ID.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the page.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 53, "title": "New Title", "slug": "rung-cutting", "description": "Accusantium harum beatae quia.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "Nostrum et modi explicabo.", "processed_html": "Nostrum et modi explicabo.
\n\n", "social_image": { "url": null }, "template": "contained", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null }, "schema": { "$ref": "#/components/schemas/Page" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "unprocessable", "content": { "application/json": { "example": { "id": 55, "title": "Eyeless in Gaza", "slug": "confuse-thirsty", "description": "Dolore iure magnam ea.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "Corporis magnam enim dolorem.", "processed_html": "Consequuntur pariatur delectus similique.
\n\n", "social_image": { "url": null }, "template": "moon", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page" } } } } }, "delete": { "summary": "remove a page", "tags": [ "pages" ], "description": "This endpoint allows the client to delete a single Page object, specified by ID.", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the page.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "id": 56, "title": "No Country for Old Men", "slug": "message_judge", "description": "Et et dolorum mollitia.", "is_top_level_path": false, "landing_page": false, "body_html": null, "body_json": null, "body_markdown": "Libero iste blanditiis et.", "processed_html": "Libero iste blanditiis et.
\n\n", "social_image": { "url": null }, "template": "contained", "subforem_id": null, "page_template_id": null, "template_data": { }, "redirect_to_url": null }, "schema": { "$ref": "#/components/schemas/Page" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "unprocessable", "content": { "application/json": { "example": { "doubled_module": { "const_name": "Page", "object": "Page" }, "__expired": false, "name": null, "__sending_message": null } } } } } } }, "/api/podcast_episodes": { "get": { "summary": "Podcast Episodes", "security": [ ], "tags": [ "podcast_episodes" ], "description": "This endpoint allows the client to retrieve a list of podcast episodes.\n \"Podcast episodes\" are episodes belonging to podcasts.\n It will only return active (reachable) podcast episodes that belong to published podcasts available on the platform, ordered by descending publication date.\n It supports pagination, each page will contain 30 articles by default.", "operationId": "getPodcastEpisodes", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "username", "in": "query", "required": false, "description": "Using this parameter will retrieve episodes belonging to a specific podcast.", "schema": { "type": "string" }, "example": "codenewbie" } ], "responses": { "200": { "description": "A List of Podcast episodes filtered by username", "content": { "application/json": { "example": [ { "type_of": "podcast_episodes", "class_name": "PodcastEpisode", "id": 42, "path": "/codenewbie/slug-2", "title": "2", "image_url": "/uploads/podcast/image/55/d8d761be-e588-4e8c-90af-5dbbebb3abfa.jpeg", "podcast": { "title": "Hennepin", "slug": "codenewbie", "image_url": "/uploads/podcast/image/55/d8d761be-e588-4e8c-90af-5dbbebb3abfa.jpeg" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PodcastEpisodeIndex" } } } } }, "404": { "description": "Unknown Podcast username", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/profile_images/{username}": { "get": { "summary": "A Users or organizations profile image", "tags": [ "profile images" ], "description": "This endpoint allows the client to retrieve a user or organization profile image information by its\n corresponding username.", "operationId": "getProfileImage", "parameters": [ { "name": "username", "in": "path", "required": true, "description": "The parameter is the username of the user or the username of the organization.", "schema": { "type": "string" }, "example": "janedoe" } ], "responses": { "200": { "description": "An object containing profile image details", "content": { "application/json": { "example": { "type_of": "profile_image", "image_of": "user", "profile_image": "/uploads/user/profile_image/4234/0984d355-dddc-4f79-9950-1702fa47ee3e.jpeg", "profile_image_90": "/uploads/user/profile_image/4234/0984d355-dddc-4f79-9950-1702fa47ee3e.jpeg" }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/ProfileImage" } } } } }, "404": { "description": "Resource Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/reactions/toggle": { "post": { "summary": "toggle reaction", "tags": [ "reactions" ], "description": "This endpoint allows the client to toggle the user's reaction to a specified reactable (eg, Article, Comment, or User). For examples:\n * \"Like\"ing an Article will create a new \"like\" Reaction from the user for that Articles\n * \"Like\"ing that Article a second time will remove the \"like\" from the user", "parameters": [ { "name": "category", "in": "query", "required": true, "schema": { "type": "string", "enum": [ "like", "unicorn", "exploding_head", "raised_hands", "fire" ] } }, { "name": "reactable_id", "in": "query", "required": true, "schema": { "type": "integer", "format": "int32" } }, { "name": "reactable_type", "in": "query", "required": true, "schema": { "type": "string", "enum": [ "Comment", "Article", "User" ] } } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "result": "create", "category": "like", "id": 161, "reactable_id": 2260, "reactable_type": "Article" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/reactions": { "post": { "summary": "create reaction", "tags": [ "reactions" ], "description": "This endpoint allows the client to create a reaction to a specified reactable (eg, Article, Comment, or User). For examples:\n * \"Like\"ing an Article will create a new \"like\" Reaction from the user for that Articles\n * \"Like\"ing that Article a second time will return the previous \"like\"", "parameters": [ { "name": "category", "in": "query", "required": true, "schema": { "type": "string", "enum": [ "like", "unicorn", "exploding_head", "raised_hands", "fire" ] } }, { "name": "reactable_id", "in": "query", "required": true, "schema": { "type": "integer", "format": "int32" } }, { "name": "reactable_type", "in": "query", "required": true, "schema": { "type": "string", "enum": [ "Comment", "Article", "User" ] } } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "result": "none", "category": "like", "id": 163, "reactable_id": 2262, "reactable_type": "Article" } } } }, "401": { "description": "unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/readinglist": { "get": { "summary": "Readinglist", "tags": [ "readinglist" ], "description": "This endpoint allows the client to retrieve a list of articles that were saved to a Users readinglist.\n It supports pagination, each page will contain `30` articles by default", "operationId": "getReadinglist", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" } ], "responses": { "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "200": { "description": "A list of articles in the users readinglist", "content": { "application/json": { "example": [ ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } } } } }, "/api/surveys": { "get": { "summary": "List surveys", "tags": [ "surveys" ], "description": "This endpoint allows the client to retrieve a list of surveys.\n\nIt supports pagination and optional filtering by active status.\n\nInternal only. Admin authorization is required to access this endpoint.", "operationId": "getSurveys", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "active", "in": "query", "required": false, "description": "Filter by active status. Omit to return all surveys.", "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "A list of surveys", "content": { "application/json": { "example": [ { "type_of": "survey", "id": 43, "title": "dolores", "slug": "dolores-2875c66f", "active": true, "display_title": true, "allow_resubmission": false, "survey_type_of": "community_pulse", "created_at": "2026-05-28T18:45:29Z", "updated_at": "2026-05-28T18:45:29Z" }, { "type_of": "survey", "id": 44, "title": "autem", "slug": "autem-1c9b1a12", "active": true, "display_title": true, "allow_resubmission": false, "survey_type_of": "community_pulse", "created_at": "2026-05-28T18:45:29Z", "updated_at": "2026-05-28T18:45:29Z" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Survey" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/surveys/{id_or_slug}": { "get": { "summary": "A survey with polls", "tags": [ "surveys" ], "description": "This endpoint allows the client to retrieve a single survey by ID or slug,\nincluding its nested polls and poll options.\n\nInternal only. Admin authorization is required to access this endpoint.", "operationId": "getSurveyByIdOrSlug", "parameters": [ { "name": "id_or_slug", "in": "path", "required": true, "description": "The ID or slug of the survey.", "schema": { "type": "string" }, "example": "community-pulse-2026" } ], "responses": { "200": { "description": "A survey with nested polls and options", "content": { "application/json": { "example": { "type_of": "survey", "id": 45, "title": "Test Survey", "slug": "test-survey-1b83c27b", "active": true, "display_title": true, "allow_resubmission": false, "survey_type_of": "community_pulse", "created_at": "2026-05-28T18:45:29Z", "updated_at": "2026-05-28T18:45:29Z", "polls": [ { "type_of": "poll", "id": 51, "prompt_markdown": "What do you think?", "prompt_html": "What do you think?\n", "position": 0, "poll_votes_count": 0, "poll_skips_count": 0, "poll_options_count": 4, "scale_min": null, "scale_max": null, "poll_type_of": "single_choice", "created_at": "2026-05-28T18:45:29Z", "updated_at": "2026-05-28T18:45:29Z", "poll_options": [ { "type_of": "poll_option", "id": 178, "markdown": "2", "processed_html": "2\n", "position": 0, "poll_votes_count": 0, "supplementary_text": null }, { "type_of": "poll_option", "id": 179, "markdown": "4", "processed_html": "4\n", "position": 1, "poll_votes_count": 0, "supplementary_text": null }, { "type_of": "poll_option", "id": 180, "markdown": "2", "processed_html": "2\n", "position": 2, "poll_votes_count": 0, "supplementary_text": null }, { "type_of": "poll_option", "id": 181, "markdown": "1", "processed_html": "1\n", "position": 3, "poll_votes_count": 0, "supplementary_text": null } ] } ] }, "schema": { "$ref": "#/components/schemas/SurveyWithPolls" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/surveys/{id_or_slug}/poll_votes": { "get": { "summary": "Survey poll votes", "tags": [ "surveys" ], "description": "This endpoint allows the client to retrieve poll votes for a given survey.\nResults are paginated. Use the `after` parameter with the last seen vote ID\nfor cursor-based pagination.\n\nInternal only. Admin authorization is required to access this endpoint.", "operationId": "getSurveyPollVotes", "parameters": [ { "name": "id_or_slug", "in": "path", "required": true, "description": "The ID or slug of the survey.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "after", "in": "query", "required": false, "description": "Return only votes with an ID greater than this value.", "schema": { "type": "integer" }, "example": 42 } ], "responses": { "200": { "description": "Poll votes", "content": { "application/json": { "example": [ { "type_of": "poll_vote", "id": 28, "poll_id": 54, "poll_option_id": 190, "user_id": 4252, "session_start": 0, "user_email": "person204@example.com", "created_at": "2026-05-28T18:45:29Z" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PollVote" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/surveys/{id_or_slug}/poll_text_responses": { "get": { "summary": "Survey poll text responses", "tags": [ "surveys" ], "description": "This endpoint allows the client to retrieve text responses for a given survey.\nResults are paginated. Use the `after` parameter with the last seen response ID\nfor cursor-based pagination.\n\nInternal only. Admin authorization is required to access this endpoint.", "operationId": "getSurveyPollTextResponses", "parameters": [ { "name": "id_or_slug", "in": "path", "required": true, "description": "The ID or slug of the survey.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/perPageParam30to1000" }, { "name": "after", "in": "query", "required": false, "description": "Return only text responses with an ID greater than this value.", "schema": { "type": "integer" }, "example": 42 } ], "responses": { "200": { "description": "Poll text responses", "content": { "application/json": { "example": [ { "type_of": "poll_text_response", "id": 12, "poll_id": 57, "user_id": 4258, "text_content": "Great survey!", "session_start": 0, "user_email": "person210@example.com", "created_at": "2026-05-28T18:45:30Z" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PollTextResponse" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Not found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/tags": { "get": { "summary": "Tags", "tags": [ "tags" ], "security": [ ], "description": "This endpoint allows the client to retrieve a list of tags that can be used to tag articles.\n\nIt will return tags ordered by popularity.\n\nIt supports pagination, each page will contain 10 tags by default.", "operationId": "getTags", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam10to1000" } ], "responses": { "200": { "description": "A List of all tags", "content": { "application/json": { "example": [ { "id": 2353, "name": "tag5", "bg_color_hex": null, "text_color_hex": null, "short_summary": null }, { "id": 2354, "name": "tag6", "bg_color_hex": null, "text_color_hex": null, "short_summary": null }, { "id": 2355, "name": "tag7", "bg_color_hex": null, "text_color_hex": null, "short_summary": null } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } } } } } } } }, "/api/trends": { "get": { "summary": "Trends", "security": [ ], "tags": [ "trends" ], "description": "This endpoint allows the client to retrieve a list of active trends.\n\nTrends represent topics or themes that are currently hot and heavily discussed in the community.\nIt will return trends ordered by score and recency.\n\nIt supports pagination, each page will contain 10 trends by default.", "operationId": "getTrends", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam10to1000" } ], "responses": { "200": { "description": "A List of Trends", "content": { "application/json": { "example": [ { "type_of": "trend", "id": 269, "name": "Ruby 3.4 release", "slug": "ruby-3-4-release", "description": "Discussions around the latest Ruby 3.4 features", "key_questions": [ ], "score": 15.5, "articles_count": 1, "cover_image": null, "first_observed_at": "2026-05-28T18:45:30Z", "last_observed_at": "2026-05-28T18:45:30Z", "created_at": "2026-05-28T18:45:30Z", "updated_at": "2026-05-28T18:45:30Z" } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Trend" } } } } } } } }, "/api/trends/{id_or_slug}": { "get": { "summary": "A Trend", "security": [ ], "tags": [ "trends" ], "description": "This endpoint allows the client to retrieve details of a single trend using either its numeric ID or unique slug.", "operationId": "getTrend", "parameters": [ { "name": "id_or_slug", "in": "path", "required": true, "description": "The ID or slug of the trend to retrieve.", "example": "ruby-3-4-release", "schema": { "type": "string" } } ], "responses": { "200": { "description": "A Trend", "content": { "application/json": { "example": { "type_of": "trend", "id": 270, "name": "Ruby 3.4 release", "slug": "ruby-3-4-release", "description": "Discussions around the latest Ruby 3.4 features", "key_questions": [ ], "score": 15.5, "articles_count": 1, "cover_image": null, "first_observed_at": "2026-05-28T18:45:30Z", "last_observed_at": "2026-05-28T18:45:30Z", "created_at": "2026-05-28T18:45:30Z", "updated_at": "2026-05-28T18:45:30Z" }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/Trend" } } } } }, "404": { "description": "Trend Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/trends/{trend_id_or_slug}/articles": { "get": { "summary": "Articles in a Trend", "security": [ ], "tags": [ "trends" ], "description": "This endpoint allows the client to retrieve a list of published articles belonging to a trend.\n\nArticles will be ordered by their proximity (distance) to the trend's centroid, then by article score.\nIt supports pagination, each page will contain 10 articles by default.", "operationId": "getTrendArticles", "parameters": [ { "name": "trend_id_or_slug", "in": "path", "required": true, "description": "The ID or slug of the trend to retrieve articles for.", "example": "ruby-3-4-release", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam10to1000" } ], "responses": { "200": { "description": "A List of Articles in the Trend", "content": { "application/json": { "example": [ { "type_of": "article", "id": 2267, "title": "Ruby 3.4 features deep dive", "description": "Put a bird on it fashion axe salvia pickled selfies pinterest. Ennui heirloom swag vhs yuccie food...", "readable_publish_date": "May 28", "slug": "ruby-34-features-deep-dive-2a22", "path": "/username218/ruby-34-features-deep-dive-2a22", "url": "http://forem.test/username218/ruby-34-features-deep-dive-2a22", "comments_count": 0, "public_reactions_count": 0, "collection_id": null, "published_timestamp": "2026-05-28T18:45:30Z", "language": "en", "subforem_id": null, "positive_reactions_count": 0, "cover_image": "http://forem.test/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", "social_image": "http://forem.test/assets/4-dcfcc4d8dd259bc0751c2de24b1cf244b181c789934368ca1cb471f0944b695d.png", "canonical_url": "http://forem.test/username218/ruby-34-features-deep-dive-2a22", "created_at": "2026-05-28T18:45:30Z", "edited_at": null, "crossposted_at": null, "published_at": "2026-05-28T18:45:30Z", "last_comment_at": "2026-05-28T18:45:30Z", "reading_time_minutes": 1, "tag_list": [ "javascript", "html", "discuss" ], "tags": "javascript, html, discuss", "user": { "name": "Jennie \"Trenton\" \\:/ Mitchell", "username": "username218", "twitter_username": "twitter218", "github_username": "github218", "user_id": 4266, "website_url": null, "profile_image": "/uploads/user/profile_image/4266/633ee7e9-0ce0-4b3b-ba3a-011971fde181.jpeg", "profile_image_90": "/uploads/user/profile_image/4266/633ee7e9-0ce0-4b3b-ba3a-011971fde181.jpeg" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ArticleIndex" } } } } }, "404": { "description": "Trend Not Found", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/users/{id}/suspend": { "put": { "summary": "Suspend a User", "tags": [ "users" ], "description": "This endpoint allows the client to suspend a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user will be assigned the 'suspended' role. Suspending a user will stop the\nuser from posting new posts and comments. It doesn't delete any of the user's content, just\nprevents them from creating new content while suspended. Users are not notified of their suspension\nin the UI, so if you want them to know about this, you must notify them.", "operationId": "suspendUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to suspend.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "User successfully unpublished" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/users/{id}/limited": { "put": { "summary": "Add limited role for a User", "tags": [ "users" ], "description": "This endpoint allows the client to limit a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user will be assigned the 'limited' role. Limiting a user will limit notifications\ngenerated from new posts and comments. It doesn't delete any of the user's content or prevent them\nfrom generating new content while limited. Users are not notified of their limits\nin the UI, so if you want them to know about this, you must notify them.", "operationId": "limitUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to limit.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "User successfully limited" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "delete": { "summary": "Remove limited for a User", "tags": [ "users" ], "description": "This endpoint allows the client to remove limits for a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user will be restored to 'general' status. Users are not notified\nof limits in the UI, so if you want them to know about this, you must\nnotify them.", "operationId": "unLimitUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to un-limit.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "User successfully un-limited" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/users/{id}/spam": { "put": { "summary": "Add spam role for a User", "tags": [ "users" ], "description": "This endpoint allows the client to add the spam role to a user.\n\n The user associated with the API key must have any 'admin' or 'moderator' role.\n\n This specified user will be assigned the 'spam' role. Addding the spam role to a user will stop the\n user from posting new posts and comments. It doesn't delete any of the user's content, just\n prevents them from creating new content while having the spam role. Users are not notified of their spaminess\n in the UI, so if you want them to know about this, you must notify them", "operationId": "spamUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to assign the spam role.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "Spam role assigned to the user successfully" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "delete": { "summary": "Remove spam role from a User", "tags": [ "users" ], "description": "This endpoint allows the client to remove the spam role for a user.\n\n The user associated with the API key must have any 'admin' or 'moderator' role.\n\n This specified user will be restored to 'general' status. Users are not notified\n of removing their spam role in the UI, so if you want them to know about this, you must\n notify them.", "operationId": "unSpamUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to remove the spam role from.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "Successfully removed the spam role from a user" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/users/{id}/trusted": { "put": { "summary": "Add trusted role for a User", "tags": [ "users" ], "description": "This endpoint allows the client to add the trusted role to a user.\n The user associated with the API key must have an 'admin' or 'moderator' role.\n The specified user will be assigned the 'trusted' role. Adding the trusted role to a user\n allows them to upvote and downvote posts and flag content that needs investigating by admins.\n Users are notified of this change in the UI, and by email.", "operationId": "trustUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to assign the trusted role.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "Trusted role assigned to the user successfully" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } }, "delete": { "summary": "Remove trusted role from a User", "tags": [ "users" ], "description": "This endpoint allows the client to remove the trusted role for a user.\n The user associated with the API key must have an 'admin' or 'moderator' role.\n The specified user will be restored to 'general' status. Users are not notified\n of removing their trusted role in the UI, so if you want them to know about this, you must\n notify them.", "operationId": "unTrustUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to remove the trusted role from.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "Successfully removed the trusted role from a user" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/users/me": { "get": { "summary": "The authenticated user", "tags": [ "users" ], "description": "This endpoint allows the client to retrieve information about the authenticated user", "operationId": "getUserMe", "responses": { "200": { "description": "successful", "content": { "application/json": { "example": { "type_of": "user", "id": 4306, "username": "username258", "name": "Vania \"Earl\" \\:/ Langworth", "twitter_username": "twitter258", "github_username": "github258", "email": null, "summary": null, "location": null, "website_url": null, "joined_at": "May 28, 2026", "profile_image": "/uploads/user/profile_image/4306/55fabae2-ecb8-4e4c-bafa-c7c9b1ed240a.jpeg", "badge_ids": [ ], "followers_count": 0 }, "schema": { "type": "object", "items": { "$ref": "#/components/schemas/MyUser" } } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } } } } }, "/api/users/{id}": { "get": { "summary": "A User", "tags": [ "users" ], "description": "This endpoint allows the client to retrieve a single user, either by id\nor by the user's username.\n\nFor complete documentation, see the v0 API docs: https://developers.forem.com/api/v0#tag/users/operation/getUser", "operationId": "getUser", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "successful", "content": { "application/json": { "schema": { "type": "object", "items": { "$ref": "#/components/schemas/ExtendedUser" } } } } } } } }, "/api/users/{id}/unpublish": { "put": { "summary": "Unpublish a User's Articles and Comments", "tags": [ "users" ], "description": "This endpoint allows the client to unpublish all of the articles and\ncomments created by a user.\n\nThe user associated with the API key must have any 'admin' or 'moderator' role.\n\nThis specified user's articles and comments will be unpublished and will no longer be\nvisible to the public. They will remain in the database and will set back to draft status\non the specified user's dashboard. Any notifications associated with the specified user's\narticles and comments will be deleted.\n\nNote this endpoint unpublishes articles and comments asychronously: it will return a 204 NO CONTENT\nstatus code immediately, but the articles and comments will not be unpublished until the\nrequest is completed on the server.", "operationId": "unpublishUser", "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The ID of the user to unpublish.", "schema": { "type": "integer", "format": "int32", "minimum": 1 }, "example": 1 } ], "responses": { "204": { "description": "User's articles and comments successfully unpublished" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "404": { "description": "Unknown User ID (still accepted for async processing)", "content": { "application/json": { "example": { "error": "not found", "status": 404 } } } } } } }, "/api/admin/users": { "post": { "summary": "Invite a User", "tags": [ "users" ], "description": "This endpoint allows the client to trigger an invitation to the provided email address.\n\n It requires a token from a user with `super_admin` privileges.", "operationId": "postAdminUsersCreate", "parameters": [ ], "responses": { "200": { "description": "Successful" }, "401": { "description": "Unauthorized", "content": { "application/json": { "example": { "error": "unauthorized", "status": 401 } } } }, "422": { "description": "Unprocessable Entity", "content": { "application/json": { "example": { "error": "param is missing or the value is empty: email", "status": 422 } } } } }, "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserInviteParam" } } } } } }, "/api/videos": { "get": { "summary": "Articles with a video", "tags": [ "videos", "articles" ], "security": [ ], "description": "This endpoint allows the client to retrieve a list of articles that are uploaded with a video.\n\nIt will only return published video articles ordered by descending popularity.\n\nIt supports pagination, each page will contain 24 articles by default.", "operationId": "videos", "parameters": [ { "$ref": "#/components/parameters/pageParam" }, { "$ref": "#/components/parameters/perPageParam24to1000" } ], "responses": { "200": { "description": "A List of all articles with videos", "content": { "application/json": { "example": [ { "type_of": "video_article", "id": 2269, "path": "/username271/dulce-et-decorum-est32-1c75", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", "video": "https://s3.amazonaws.com/dev-to-input-v0/video-upload__2d7dc29e39a40c7059572bca75bb646b", "title": "Dulce et Decorum Est32", "user_id": 4320, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { "name": "Layne \"Eldon\" \\:/ Satterfield" } }, { "type_of": "video_article", "id": 2270, "path": "/username272/an-evil-cradling33-n2e", "cloudinary_video_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/thumbs-video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f-00001.png", "video": "https://s3.amazonaws.com/dev-to-input-v0/video-upload__2d7dc29e39a40c7059572bca75bb646b", "title": "An Evil Cradling33", "user_id": 4321, "video_duration_in_minutes": "00:00", "video_source_url": "https://dw71fyauz7yz9.cloudfront.net/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f/video-upload__1e42eb0bab4abb3c63baeb5e8bdfe69f.m3u8", "user": { "name": "Foster \"Augustine\" \\:/ Cruickshank" } } ], "schema": { "type": "array", "items": { "$ref": "#/components/schemas/VideoArticle" } } } } } } } } }, "servers": [ { "url": "https://dev.to/api", "description": "Production server" } ], "security": [ { "api-key": [ ] } ], "components": { "securitySchemes": { "api-key": { "type": "apiKey", "name": "api-key", "in": "header", "description": "API Key authentication.\n\nAuthentication for some endpoints, like write operations on the\nArticles API require a DEV API key.\n\nAll authenticated endpoints are CORS disabled, the API key is intended for non-browser scripts.\n\n### Getting an API key\n\nTo obtain one, please follow these steps:\n\n - visit https://dev.to/settings/extensions\n - in the \"DEV API Keys\" section create a new key by adding a\n description and clicking on \"Generate API Key\"\n\n \n\n - You'll see the newly generated key in the same view\n " } }, "parameters": { "pageParam": { "in": "query", "name": "page", "required": false, "description": "Pagination page", "schema": { "type": "integer", "format": "int32", "minimum": 1, "default": 1 } }, "perPageParam10to1000": { "in": "query", "name": "per_page", "required": false, "description": "Page size (the number of items to return per page). The default maximum value can be overridden by \"API_PER_PAGE_MAX\" environment variable.", "schema": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 1000, "default": 10 } }, "perPageParam24to1000": { "in": "query", "name": "per_page", "required": false, "description": "Page size (the number of items to return per page). The default maximum value can be overridden by \"API_PER_PAGE_MAX\" environment variable.", "schema": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 1000, "default": 24 } }, "perPageParam30to1000": { "in": "query", "name": "per_page", "required": false, "description": "Page size (the number of items to return per page). The default maximum value can be overridden by \"API_PER_PAGE_MAX\" environment variable.", "schema": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 1000, "default": 30 } }, "perPageParam30to100": { "in": "query", "name": "per_page", "required": false, "description": "Page size (the number of items to return per page). The default maximum value can be overridden by \"API_PER_PAGE_MAX\" environment variable.", "schema": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 100, "default": 30 } }, "perPageParam80to1000": { "in": "query", "name": "per_page", "required": false, "description": "Page size (the number of items to return per page). The default maximum value can be overridden by \"API_PER_PAGE_MAX\" environment variable.", "schema": { "type": "integer", "format": "int32", "minimum": 1, "maximum": 1000, "default": 80 } }, "listingCategoryParam": { "name": "category", "in": "query", "description": "Using this parameter will return listings belonging to the\n requested category.", "schema": { "type": "string" }, "example": "cfp" } }, "schemas": { "ArticleFlareTag": { "description": "Flare tag of the article", "type": "object", "properties": { "name": { "type": "string" }, "bg_color_hex": { "description": "Background color (hexadecimal)", "type": "string", "nullable": true }, "text_color_hex": { "description": "Text color (hexadecimal)", "type": "string", "nullable": true } } }, "ArticleIndex": { "description": "Representation of an article or post returned in a list", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int32" }, "title": { "type": "string" }, "description": { "type": "string" }, "cover_image": { "type": "string", "format": "url", "nullable": true }, "readable_publish_date": { "type": "string" }, "social_image": { "type": "string", "format": "url" }, "tag_list": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "string" }, "slug": { "type": "string" }, "path": { "type": "string", "format": "path" }, "url": { "type": "string", "format": "url" }, "canonical_url": { "type": "string", "format": "url" }, "positive_reactions_count": { "type": "integer", "format": "int32" }, "public_reactions_count": { "type": "integer", "format": "int32" }, "created_at": { "type": "string", "format": "date-time" }, "edited_at": { "type": "string", "format": "date-time", "nullable": true }, "crossposted_at": { "type": "string", "format": "date-time", "nullable": true }, "published_at": { "type": "string", "format": "date-time" }, "last_comment_at": { "type": "string", "format": "date-time" }, "published_timestamp": { "description": "Crossposting or published date time", "type": "string", "format": "date-time" }, "reading_time_minutes": { "description": "Reading time, in minutes", "type": "integer", "format": "int32" }, "user": { "$ref": "#/components/schemas/SharedUser" }, "flare_tag": { "$ref": "#/components/schemas/ArticleFlareTag" }, "organization": { "$ref": "#/components/schemas/SharedOrganization" } }, "required": [ "type_of", "id", "title", "description", "cover_image", "readable_publish_date", "social_image", "tag_list", "tags", "slug", "path", "url", "canonical_url", "comments_count", "positive_reactions_count", "public_reactions_count", "created_at", "edited_at", "crossposted_at", "published_at", "last_comment_at", "published_timestamp", "user", "reading_time_minutes" ] }, "VideoArticle": { "description": "Representation of an Article with video", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int64" }, "path": { "type": "string" }, "cloudinary_video_url": { "type": "string" }, "title": { "type": "string" }, "user_id": { "type": "integer", "format": "int64" }, "video_duration_in_minutes": { "type": "string" }, "video_source_url": { "type": "string" }, "user": { "description": "Author of the article", "type": "object", "properties": { "name": { "type": "string" } } } } }, "Article": { "description": "Representation of an Article to be created/updated", "type": "object", "properties": { "article": { "type": "object", "properties": { "title": { "type": "string" }, "body_markdown": { "type": "string" }, "published": { "type": "boolean", "default": false }, "series": { "type": "string", "nullable": true }, "main_image": { "type": "string", "nullable": true }, "canonical_url": { "type": "string", "nullable": true }, "description": { "type": "string" }, "tags": { "type": "string" }, "organization_id": { "type": "integer", "nullable": true } } } } }, "Organization": { "description": "Representation of an Organization", "type": "object", "properties": { "type_of": { "type": "string" }, "username": { "type": "string" }, "name": { "type": "string" }, "summary": { "type": "string" }, "twitter_username": { "type": "string" }, "github_username": { "type": "string" }, "url": { "type": "string" }, "location": { "type": "string" }, "joined_at": { "type": "string" }, "tech_stack": { "type": "string" }, "tag_line": { "type": "string", "nullable": true }, "story": { "type": "string", "nullable": true } } }, "FollowedTag": { "description": "Representation of a followed tag", "type": "object", "properties": { "id": { "description": "Tag id", "type": "integer", "format": "int64" }, "name": { "type": "string" }, "points": { "type": "number", "format": "float" } }, "required": [ "id", "name", "points" ] }, "Tag": { "description": "Representation of a tag", "type": "object", "properties": { "id": { "description": "Tag id", "type": "integer", "format": "int64" }, "name": { "type": "string" }, "bg_color_hex": { "type": "string", "nullable": true }, "text_color_hex": { "type": "string", "nullable": true } } }, "Page": { "description": "Representation of a page object", "type": "object", "properties": { "title": { "type": "string", "description": "Title of the page" }, "slug": { "type": "string", "description": "Used to link to this page in URLs, must be unique and URL-safe" }, "description": { "type": "string", "description": "For internal use, helps similar pages from one another" }, "body_markdown": { "type": "string", "description": "The text (in markdown) of the ad (required)", "nullable": true }, "body_json": { "type": "string", "description": "For JSON pages, the JSON body", "nullable": true }, "is_top_level_path": { "type": "boolean", "description": "If true, the page is available at '/{slug}' instead of '/page/{slug}', use with caution" }, "social_image": { "type": "object", "nullable": true }, "template": { "type": "string", "enum": [ "contained", "full_within_layout", "nav_bar_included", "json", "css", "txt" ], "default": "contained", "description": "Controls what kind of layout the page is rendered in" } }, "required": [ "title", "slug", "description", "template" ] }, "PodcastEpisodeIndex": { "description": "Representation of a podcast episode returned in a list", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int32" }, "class_name": { "type": "string" }, "path": { "type": "string", "format": "path" }, "title": { "type": "string" }, "image_url": { "description": "Podcast episode image url or podcast image url", "type": "string", "format": "url" }, "podcast": { "$ref": "#/components/schemas/SharedPodcast" } }, "required": [ "type_of", "class_name", "id", "path", "title", "image_url", "podcast" ] }, "ProfileImage": { "description": "A profile image object", "type": "object", "properties": { "type_of": { "description": "Return profile_image", "type": "string" }, "image_of": { "description": "Determines the type of the profile image owner (user or organization)", "type": "string" }, "profile_image": { "description": "Profile image (640x640)", "type": "string" }, "profile_image_90": { "description": "Profile image (90x90)", "type": "string" } } }, "SharedUser": { "description": "The resource creator", "type": "object", "properties": { "name": { "type": "string" }, "username": { "type": "string" }, "twitter_username": { "type": "string", "nullable": true }, "github_username": { "type": "string", "nullable": true }, "website_url": { "type": "string", "format": "url", "nullable": true }, "profile_image": { "description": "Profile image (640x640)", "type": "string" }, "profile_image_90": { "description": "Profile image (90x90)", "type": "string" } } }, "SharedOrganization": { "description": "The organization the resource belongs to", "type": "object", "properties": { "name": { "type": "string" }, "username": { "type": "string" }, "slug": { "type": "string" }, "profile_image": { "description": "Profile image (640x640)", "type": "string", "format": "url" }, "profile_image_90": { "description": "Profile image (90x90)", "type": "string", "format": "url" } } }, "User": { "description": "The representation of a user returned in a list", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "name": { "type": "string" }, "summary": { "type": "string", "nullable": true }, "twitter_username": { "type": "string" }, "github_username": { "type": "string" }, "website_url": { "type": "string", "nullable": true }, "location": { "type": "string", "nullable": true }, "joined_at": { "type": "string" }, "profile_image": { "type": "string" } } }, "ExtendedUser": { "description": "The representation of a user", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "name": { "type": "string" }, "summary": { "type": "string", "nullable": true }, "twitter_username": { "type": "string" }, "github_username": { "type": "string" }, "email": { "type": "string", "nullable": true, "description": "Email (if user allows displaying email on their profile) or nil" }, "website_url": { "type": "string", "nullable": true }, "location": { "type": "string", "nullable": true }, "joined_at": { "type": "string" }, "profile_image": { "type": "string" }, "badge_ids": { "type": "array", "items": { "type": "integer" }, "description": "ids of the badges awarded to the user" } } }, "MyUser": { "description": "The representation of a user when accessed by themselves", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "name": { "type": "string" }, "summary": { "type": "string", "nullable": true }, "twitter_username": { "type": "string" }, "github_username": { "type": "string" }, "email": { "type": "string", "nullable": true, "description": "Email (if user allows displaying email on their profile) or nil" }, "website_url": { "type": "string", "nullable": true }, "location": { "type": "string", "nullable": true }, "joined_at": { "type": "string" }, "profile_image": { "type": "string" }, "badge_ids": { "type": "array", "items": { "type": "integer" }, "description": "ids of the badges awarded to the user" }, "followers_count": { "type": "integer" } } }, "SharedPodcast": { "description": "The podcast that the resource belongs to", "type": "object", "properties": { "title": { "type": "string" }, "slug": { "type": "string" }, "image_url": { "description": "Podcast image url", "type": "string", "format": "url" } } }, "Comment": { "description": "A Comment on an Article or Podcast Episode", "type": "object", "properties": { "type_of": { "type": "string" }, "id_code": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "image_url": { "description": "Podcast image url", "type": "string", "format": "url" } } }, "UserInviteParam": { "description": "User invite parameters", "type": "object", "properties": { "email": { "type": "string" }, "name": { "type": "string", "nullable": true } } }, "Billboard": { "description": "Billboard, aka Widget, ex. Display Ad", "type": "object", "properties": { "id": { "type": "integer", "description": "The ID of the Billboard" }, "name": { "type": "string", "description": "For internal use, helps distinguish ads from one another" }, "body_markdown": { "type": "string", "description": "The text (in markdown) of the ad (required)" }, "approved": { "type": "boolean", "description": "Ad must be both published and approved to be in rotation" }, "published": { "type": "boolean", "description": "Ad must be both published and approved to be in rotation" }, "expires_at": { "type": "string", "format": "date-time", "nullable": true, "description": "Timestamp when the billboard expires. After this time, the billboard will automatically be marked as not approved." }, "organization_id": { "type": "integer", "description": "Identifies the organization to which the ad belongs", "nullable": true }, "creator_id": { "type": "integer", "description": "Identifies the user who created the ad.", "nullable": true }, "placement_area": { "type": "string", "enum": [ "sidebar_left", "sidebar_left_2", "sidebar_right", "sidebar_right_second", "sidebar_right_third", "feed_first", "feed_second", "feed_third", "home_hero", "footer", "page_fixed_bottom", "post_fixed_bottom", "post_body_bottom", "post_sidebar", "post_comments", "post_comments_mid", "digest_first", "digest_second" ], "description": "Identifies which area of site layout the ad can appear in" }, "tag_list": { "type": "string", "description": "Tags on which this ad can be displayed (blank is all/any tags)" }, "exclude_article_ids": { "type": "string", "nullable": true, "description": "Articles this ad should *not* appear on (blank means no articles are disallowed, and this ad can appear next to any/all articles). Comma-separated list of integer Article IDs" }, "audience_segment_id": { "type": "integer", "description": "Specifies a specific audience segment who will see this billboard" }, "audience_segment_type": { "type": "string", "enum": [ "manual", "trusted", "posted", "no_posts_yet", "dark_theme", "light_theme", "no_experience", "experience1", "experience2", "experience3", "experience4", "experience5" ], "description": "Specifies a group of users who will see this billboard (must match audience_segment_id if both provided)" }, "target_geolocations": { "type": "array", "items": { "type": "string" }, "description": "Locations to show this billboard in (blank means it will be shown in all locations). Specified as a comma-separated list or array of ISO 3166-2 country and optionally region codes)" }, "display_to": { "type": "string", "enum": [ "all", "logged_in", "logged_out" ], "default": "all", "description": "Potentially limits visitors to whom the ad is visible" }, "type_of": { "type": "string", "enum": [ "in_house", "community", "external" ], "default": "in_house", "description": "Types of the billboards:\nin_house (created by admins),\ncommunity (created by an entity, appears on entity's content),\nexternal ( created by an entity, or a non-entity, can appear everywhere)\n" } }, "required": [ "name", "body_markdown", "placement_area" ] }, "Segment": { "description": "A manually managed audience segment", "type": "object", "properties": { "id": { "type": "integer", "description": "The ID of the segment" }, "type_of": { "type": "string", "enum": [ "manual" ], "default": "manual", "description": "Marks the segment as manually managed (other types are internal)" }, "user_count": { "type": "integer", "description": "The current number of users in the segment" } } }, "SegmentUserIds": { "type": "object", "properties": { "user_ids": { "type": "array", "items": { "type": "integer" }, "maxItems": 10000 } } }, "AgentSessionIndex": { "description": "Representation of an agent session returned in a list or after creation", "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "slug": { "type": "string" }, "title": { "type": "string" }, "tool_name": { "type": "string", "description": "Tool that produced the session (e.g. claude_code, codex)" }, "total_messages": { "type": "integer", "format": "int32" }, "published": { "type": "boolean" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "url": { "type": "string", "format": "url" } }, "required": [ "id", "slug", "title", "tool_name", "total_messages", "published", "created_at", "url" ] }, "AgentSessionShow": { "description": "Full representation of an agent session including messages and curation data", "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "slug": { "type": "string" }, "title": { "type": "string" }, "tool_name": { "type": "string", "description": "Tool that produced the session (e.g. claude_code, codex)" }, "total_messages": { "type": "integer", "format": "int32" }, "curated_count": { "type": "integer", "format": "int32", "description": "Number of curated messages selected for display" }, "published": { "type": "boolean" }, "metadata": { "type": "object", "nullable": true, "description": "Session metadata (tool-specific)" }, "messages": { "type": "array", "items": { "type": "object" }, "description": "All normalized messages in the session" }, "slices": { "type": "array", "items": { "type": "object" }, "description": "Named slices grouping message ranges" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "url": { "type": "string", "format": "url" } }, "required": [ "id", "slug", "title", "tool_name", "total_messages", "curated_count", "published", "messages", "slices", "created_at", "updated_at", "url" ] }, "PollOption": { "description": "A single option within a poll", "type": "object", "properties": { "type_of": { "type": "string", "enum": [ "poll_option" ], "description": "Resource discriminator" }, "id": { "type": "integer", "format": "int64" }, "markdown": { "type": "string", "nullable": true, "description": "Option text in markdown" }, "processed_html": { "type": "string", "nullable": true, "description": "Option text rendered as HTML" }, "position": { "type": "integer", "format": "int32", "description": "Display order within the poll" }, "poll_votes_count": { "type": "integer", "format": "int32", "description": "Number of votes for this option" }, "supplementary_text": { "type": "string", "nullable": true, "description": "Additional descriptive text for the option" } }, "required": [ "type_of", "id", "markdown", "processed_html", "position", "poll_votes_count" ] }, "Poll": { "description": "A poll (question) belonging to a survey or article", "type": "object", "properties": { "type_of": { "type": "string", "enum": [ "poll" ], "description": "Resource discriminator" }, "id": { "type": "integer", "format": "int64" }, "prompt_markdown": { "type": "string", "nullable": true, "description": "Question text in markdown" }, "prompt_html": { "type": "string", "nullable": true, "description": "Question text rendered as HTML" }, "poll_type_of": { "type": "string", "enum": [ "single_choice", "multiple_choice", "scale", "text_input" ], "description": "Poll question type: single_choice, multiple_choice, scale, or text_input" }, "position": { "type": "integer", "format": "int32", "description": "Display order within the survey" }, "poll_votes_count": { "type": "integer", "format": "int32", "description": "Total number of votes across all options" }, "poll_skips_count": { "type": "integer", "format": "int32", "description": "Number of users who skipped this poll" }, "poll_options_count": { "type": "integer", "format": "int32", "description": "Number of options in this poll" }, "scale_min": { "type": "integer", "format": "int32", "nullable": true, "description": "Minimum value for scale polls" }, "scale_max": { "type": "integer", "format": "int32", "nullable": true, "description": "Maximum value for scale polls" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "poll_options": { "type": "array", "items": { "$ref": "#/components/schemas/PollOption" }, "description": "The available options for this poll" } }, "required": [ "type_of", "id", "prompt_markdown", "prompt_html", "poll_type_of", "position", "poll_votes_count", "poll_skips_count", "poll_options_count", "created_at", "updated_at", "poll_options" ] }, "Survey": { "description": "Representation of a survey", "type": "object", "properties": { "type_of": { "type": "string", "enum": [ "survey" ], "description": "Resource discriminator" }, "id": { "type": "integer", "format": "int64" }, "title": { "type": "string" }, "slug": { "type": "string" }, "survey_type_of": { "type": "string", "enum": [ "community_pulse", "industry", "fun" ], "description": "Survey category" }, "active": { "type": "boolean", "nullable": true, "description": "Whether the survey is currently active" }, "display_title": { "type": "boolean", "description": "Whether to show the title to respondents" }, "allow_resubmission": { "type": "boolean", "description": "Whether users can submit multiple times" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } }, "required": [ "type_of", "id", "title", "slug", "survey_type_of", "display_title", "allow_resubmission", "created_at", "updated_at" ] }, "SurveyWithPolls": { "description": "Representation of a survey including its polls and poll options", "allOf": [ { "$ref": "#/components/schemas/Survey" }, { "type": "object", "properties": { "polls": { "type": "array", "items": { "$ref": "#/components/schemas/Poll" }, "description": "All polls in the survey, ordered by position" } }, "required": [ "polls" ] } ] }, "PollVote": { "description": "Representation of a single poll vote cast by a user", "type": "object", "properties": { "type_of": { "type": "string", "enum": [ "poll_vote" ], "description": "Resource discriminator" }, "id": { "type": "integer", "format": "int64" }, "poll_id": { "type": "integer", "format": "int64" }, "poll_option_id": { "type": "integer", "format": "int64" }, "user_id": { "type": "integer", "format": "int64" }, "user_email": { "type": "string", "format": "email" }, "session_start": { "type": "integer", "format": "int32" }, "created_at": { "type": "string", "format": "date-time" } }, "required": [ "type_of", "id", "poll_id", "poll_option_id", "user_id", "user_email", "session_start", "created_at" ] }, "PollTextResponse": { "description": "Representation of a free-text response to a text-input poll", "type": "object", "properties": { "type_of": { "type": "string", "enum": [ "poll_text_response" ], "description": "Resource discriminator" }, "id": { "type": "integer", "format": "int64" }, "poll_id": { "type": "integer", "format": "int64" }, "user_id": { "type": "integer", "format": "int64" }, "user_email": { "type": "string", "format": "email" }, "text_content": { "type": "string" }, "session_start": { "type": "integer", "format": "int32" }, "created_at": { "type": "string", "format": "date-time" } }, "required": [ "type_of", "id", "poll_id", "user_id", "user_email", "text_content", "session_start", "created_at" ] }, "Trend": { "description": "Representation of a trend", "type": "object", "properties": { "type_of": { "type": "string" }, "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "slug": { "type": "string" }, "description": { "type": "string", "nullable": true }, "key_questions": { "type": "array", "items": { "type": "string" } }, "score": { "type": "number", "format": "float" }, "articles_count": { "type": "integer", "format": "int32" }, "cover_image": { "type": "string", "format": "url", "nullable": true }, "first_observed_at": { "type": "string", "format": "date-time" }, "last_observed_at": { "type": "string", "format": "date-time" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } }, "required": [ "type_of", "id", "name", "slug", "key_questions", "score", "articles_count", "first_observed_at", "last_observed_at", "created_at", "updated_at" ] } } } }