Read one article, including its content. This is the only operation
that returns a body.
The same two gates apply as on the list. An article stamped with an
audience answers 404 to a key that does not hold that audience, and a
future dated article answers 404 until it goes live, including to the
newsletter's own team, so that a preview link cannot be shared early.
For a natively published issue, content is the email rendered to HTML
with personalization placeholders resolved against an empty context, so
a merge tag never leaks as raw text. For an imported issue it is the
body as it arrived from the provider.
?expand=content adds content_markdown, the same body as Markdown.
Ask for it when a model is going to read the issue, and ask for
?fields=content_markdown with it to leave the HTML behind entirely.
Headers
-
The contract version this request is written against, as a release date (
YYYY-MM-DD). Omitting the header pins the request to the version that was current when the API key was issued, so an integration keeps working when a newer version ships. An unknown value answers400withinvalid_version.
Path parameters
-
The article's
id(a UUID) or itsshort_id, an eight character base62 string that is unique across Commune. Theslugis not accepted here because it is unique only within a newsletter.
Query parameters
-
Comma separated list of relationship paths to inline in the response. Unexpanded relationships are returned as a reference object carrying only
idandobject. Each operation documents the paths it accepts, and an unknown path answers400. Nested paths use a dot, for examplearticle.newsletter.One accepted path is not a relationship.
?expand=contentonGET /articles/{article}adds the Markdown rendition of the body beside the HTML one. It is the same trade the parameter always offers, a fuller response for a larger one, over a property that has more than one representation rather than over a reference. -
Comma separated allow list of top level properties to return on each object, so a client can trim a response it does not need in full.
idandobjectare always returned. An unknown property name answers400. Properties omitted by an operation, such ascontenton any article list, cannot be brought back withfields.A trimmed body is a subset of the schema this operation declares, and a property that schema marks required is absent when it was not asked for. That is the point of the parameter, so a client that validates responses against the schema either sends no
fieldsor relaxesrequired.
Responses
-
The article, with
content. -
The request was malformed: an unknown query parameter, an unparseable cursor, an unknown
expandpath, or an unrecognisedCommune-Version. -
No API key was presented, or the key is unknown, revoked or expired.
All four answer identically, down to the wording. Saying that a key was revoked rather than never issued confirms to whoever is holding the string that it was once real, which a legitimate caller does not need and a thief should not get.
-
No such resource, or the key is not allowed to know that it exists. Commune answers
404rather than403where distinguishing the two would leak the existence of private content. -
Too many requests. Back off and retry after the interval named by the
Retry-Afterresponse header. -
Something failed inside Commune. The request may be retried.
curl https://api.usecommune.com/articles/k7Rm2xQp \
-H "Authorization: Bearer $COMMUNE_API_KEY" \
-H "Commune-Version: 2026-08-26"
curl \
--request GET 'https://api.usecommune.com/articles/k7Rm2xQp' \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Commune-Version: 2026-08-26"
{
"object": "article",
"id": "string",
"short_id": "k7Rm2xQp",
"slug": "string",
"newsletter": {
"object": "newsletter",
"id": "9a4c1c6e-0f2b-4f47-9d3f-6d1b1a2c3d4e"
},
"title": "string",
"preview_text": "string",
"image_url": "https://example.com",
"external_url": "https://example.com",
"status": "draft",
"is_imported": true,
"posted_at": "2026-05-04T09:42:00Z",
"authors": [
{
"object": "newsletter",
"id": "9a4c1c6e-0f2b-4f47-9d3f-6d1b1a2c3d4e"
}
],
"thread": {
"object": "newsletter",
"id": "9a4c1c6e-0f2b-4f47-9d3f-6d1b1a2c3d4e"
},
"stats": {
"likes": 42,
"comments": 42,
"highlights": 42
},
"created_at": "2026-05-04T09:42:00Z",
"updated_at": "2026-05-04T09:42:00Z",
"content": "string",
"content_markdown": "string"
}
{
"error": {
"code": "bad_request",
"message": "Newsletter not found.",
"param": "cursor",
"allowed_values": [
"subscribed",
"unsubscribed",
"bounced",
"complained",
"pending"
],
"request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
"docs_url": "https://usecommune.com/docs/api/errors#not_found"
}
}
# Headers
WWW-Authenticate: string
# Payload
{
"error": {
"code": "bad_request",
"message": "Newsletter not found.",
"param": "cursor",
"allowed_values": [
"subscribed",
"unsubscribed",
"bounced",
"complained",
"pending"
],
"request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
"docs_url": "https://usecommune.com/docs/api/errors#not_found"
}
}
{
"error": {
"code": "bad_request",
"message": "Newsletter not found.",
"param": "cursor",
"allowed_values": [
"subscribed",
"unsubscribed",
"bounced",
"complained",
"pending"
],
"request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
"docs_url": "https://usecommune.com/docs/api/errors#not_found"
}
}
# Headers
Retry-After: 42
# Payload
{
"error": {
"code": "bad_request",
"message": "Newsletter not found.",
"param": "cursor",
"allowed_values": [
"subscribed",
"unsubscribed",
"bounced",
"complained",
"pending"
],
"request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
"docs_url": "https://usecommune.com/docs/api/errors#not_found"
}
}
{
"error": {
"code": "bad_request",
"message": "Newsletter not found.",
"param": "cursor",
"allowed_values": [
"subscribed",
"unsubscribed",
"bounced",
"complained",
"pending"
],
"request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
"docs_url": "https://usecommune.com/docs/api/errors#not_found"
}
}