How one issue did on both sides at once: what the email did, and what the community did with it afterwards. No email provider can return the right hand column, because the reading, highlighting and arguing happened on Commune.
email is present only for an issue Commune sent itself. For an issue
imported from an outside provider it is null, because that provider
mailed it and never handed Commune the per recipient outcome. It is
null for an issue that has not been sent yet as well.
community is computed at read time and keeps counting long after the
send, so two reads a week apart legitimately disagree.
Creator scope. The public tallies on an article, which are likes,
comments and highlights, live on the article itself and need no
creator key.
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's email and community performance.
-
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.
-
The key is valid but is not allowed to read this. Either it carries public scope and the operation needs creator scope, or it is bound to a different newsletter than the one addressed.
-
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/stats \
-H "Authorization: Bearer $COMMUNE_API_KEY" \
-H "Commune-Version: 2026-08-26"
curl \
--request GET 'https://api.usecommune.com/articles/k7Rm2xQp/stats' \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Commune-Version: 2026-08-26"
{
"object": "article_stats",
"article": {
"object": "newsletter",
"id": "9a4c1c6e-0f2b-4f47-9d3f-6d1b1a2c3d4e"
},
"email": {
"recipients": 42,
"delivered": 42,
"opened": 42,
"clicked": 42,
"bounced": 42,
"unsubscribed": 42
},
"community": {
"views": 42,
"likes": 42,
"saves": 42,
"highlights": 42,
"thread_messages": 42,
"participants": 42
}
}
{
"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"
}
}
{
"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"
}
}