curl --request GET \
--url https://api.athenahq.ai/api/v1/content/items \
--header 'x-api-key: <api-key>'import requests
url = "https://api.athenahq.ai/api/v1/content/items"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.athenahq.ai/api/v1/content/items', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.athenahq.ai/api/v1/content/items",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.athenahq.ai/api/v1/content/items"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.athenahq.ai/api/v1/content/items")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.athenahq.ai/api/v1/content/items")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"content": [
{
"content_id": "11111111-2222-3333-4444-555555555555",
"title": "How to Apply Foundation on Mature Skin",
"type": "draft",
"stage": "generated",
"url": null,
"normalized_url": null,
"sheet_id": "00000000-0000-4000-8000-000000000001",
"sheet_name": "Drafts - sprint 1",
"topic_name": "Makeup for Mature Skin",
"prompt_ids": [
"aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"
],
"prompt_count": 1,
"mark_as_done_time": null,
"created_at": "2026-09-01T20:59:53.000Z",
"updated_at": "2026-09-01T21:09:04.000Z"
}
],
"pagination": {
"page_num": 0,
"page_size": 50,
"has_more": false
}
}List Content Items
Returns every content item in a website’s Content Hub, published or not: in-flight drafts, briefs, snipes, optimize and slice runs, scheduled and failed items, plus tracked pages. This is the enumeration path from a sheet_id to its unpublished rows. POST /api/v1/content lists only finished pipeline rows, with citation and impression metrics, so a sheet full of generated drafts appears empty there; use this endpoint to see them.
Returns identity fields only (id, title, type, stage, sheet, URL, timestamps, target prompt ids), no metrics. Reads from the primary store and is uncached, so an item is listable the moment POST /api/v1/content/generate returns its content_id. Read a row’s text with GET /api/v1/content/{content_id}.
stage is the raw pipeline workflow state, not a publication flag: null means no pipeline record (most external and imported tracked pages), and manual editor items carry generated. Treat an item as published only when its stage is done (or it is an external or imported page) and it has a url; done without a url is an unpublished orphan.
Passing the sheet_id of a view-type tab (see sheet_type on GET /api/v1/content/sheets) lists the shared main pool without the view’s saved filters. Hidden content (is_hidden = true) is excluded. Pagination uses page_size + 1 lookahead: pagination.has_more === true means the next page exists; there is no total-count field. Pass an unknown sheet_id or prompt_id (or one from another website) and the endpoint returns 403.
Also exposed as the MCP tool list_content.
curl --request GET \
--url https://api.athenahq.ai/api/v1/content/items \
--header 'x-api-key: <api-key>'import requests
url = "https://api.athenahq.ai/api/v1/content/items"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.athenahq.ai/api/v1/content/items', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.athenahq.ai/api/v1/content/items",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.athenahq.ai/api/v1/content/items"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.athenahq.ai/api/v1/content/items")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.athenahq.ai/api/v1/content/items")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"content": [
{
"content_id": "11111111-2222-3333-4444-555555555555",
"title": "How to Apply Foundation on Mature Skin",
"type": "draft",
"stage": "generated",
"url": null,
"normalized_url": null,
"sheet_id": "00000000-0000-4000-8000-000000000001",
"sheet_name": "Drafts - sprint 1",
"topic_name": "Makeup for Mature Skin",
"prompt_ids": [
"aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"
],
"prompt_count": 1,
"mark_as_done_time": null,
"created_at": "2026-09-01T20:59:53.000Z",
"updated_at": "2026-09-01T21:09:04.000Z"
}
],
"pagination": {
"page_num": 0,
"page_size": 50,
"has_more": false
}
}Query Parameters
The website whose Content Hub to enumerate.
Restrict to a single Content Hub tab. Use GET /api/v1/content/sheets to discover IDs. A view-type tab resolves to the shared main pool. Omit to span every tab.
Restrict to a single content type. athena_created is a shortcut for the four Athena-generated subtypes (draft, snipe, optimize, slice). Omit to span every type.
external, imported, athena_created, draft, snipe, optimize, slice, manual Restrict to a single pipeline stage. Matches the pipeline record only, so it can never match rows without one (most external and imported pages). Omit to span every stage.
scheduled, pending, pending_brief, generated_brief, pending_article, generated, done, failed Restrict to items written for this prompt (their targeting, the same prompt ids POST /api/v1/content/generate takes). Soft-deleted prompts still match.
Zero-indexed page number.
x >= 0Number of items per page (1-100).
1 <= x <= 100Response
Successful response with the page of content items.
Was this page helpful?