Commune · Schema

DeliveryAttempt

One handover of one event to one destination, and what came of it. A record of something that happened rather than a thing with a state: it never changes after it is written, and a retry is a second `DeliveryAttempt` with a higher `attempt` rather than an edit to this one. **Two fields a reader might expect are not here.** The body your endpoint answered with is never returned, since a refusing endpoint routinely writes the request back into its own response, credentials included. Neither is the event's payload: several topics carry a subscriber's email address, and returning it here would make every read of this log a read of audience data. `event_id` names the event, `event_type` says which topic it was, and `response_status` says what the endpoint answered.

NewslettersEmailCommunityPublishingCreator EconomySubscribersWebhooksMCPAnalyticsContent

Properties

Name Type Description
object string Always `delivery_attempt`.
id string The delivery service's identifier for this attempt. Opaque, and not a UUID: it is minted on the other side of the handover.
newsletter object The newsletter whose event this was. A `Ref` unless `newsletter` is named in `?expand=`.
destination object Where this was delivered. Always a `Ref`, whose `id` matches a row from `GET /newsletters/{newsletter}/destinations`. A destination deleted since the attempt was made still appears here, because the a
destination_type string What kind of target it was, as the delivery service named it at the time. Free text for the same reason `Destination.type` is: the vocabulary belongs to the delivery service and grows there.
event_id string The event that was being delivered, by the `id` on its envelope. The same string the consumer receives in the `Commune-Event-Id` header, which makes it the one identifier both sides share and the thin
event_type stringnull The topic, matching the keys of the `webhooks` block of this document. Null only if the delivery service no longer holds the event this attempt belonged to.
status object How this attempt ended.
response_status integernull The HTTP status the destination answered with. Null when it did not answer at all, in which case `failure` says why.
failure stringnull Why there was no answer, when there was none: `timeout` is the common one. Null whenever `response_status` is set, and the two are never both set or both null. Free text, so treat an unrecognised valu
attempt integer 1 on the first delivery of this event to this destination, and one higher on each retry of it. The number the `Commune-Delivery-Attempt` header would carry if it were sent.
manual boolean Whether somebody asked for this attempt rather than the delivery service making it on its own. True for one made by `POST /delivery-attempts/{attempt}/replay` or by the retry button in the portal, and
created_at string When the attempt was made.
View JSON Schema on GitHub

JSON Schema

usecommune-delivery-attempt-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/usecommune/main/json-schema/usecommune-delivery-attempt-schema.json",
  "title": "DeliveryAttempt",
  "description": "One handover of one event to one destination, and what came of it.\n\nA record of something that happened rather than a thing with a state:\nit never changes after it is written, and a retry is a second\n`DeliveryAttempt` with a higher `attempt` rather than an edit to this\none.\n\n**Two fields a reader might expect are not here.** The body your\nendpoint answered with is never returned, since a refusing endpoint\nroutinely writes the request back into its own response, credentials\nincluded. Neither is the event's payload: several topics carry a\nsubscriber's email address, and returning it here would make every read\nof this log a read of audience data. `event_id` names the event,\n`event_type` says which\ntopic it was, and `response_status` says what the endpoint answered.\n",
  "x-generated": "2026-10-07",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/usecommune-openapi.yml#/components/schemas/DeliveryAttempt",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "object",
    "id",
    "newsletter",
    "destination",
    "event_id",
    "event_type",
    "status",
    "response_status",
    "failure",
    "attempt",
    "manual",
    "created_at"
  ],
  "properties": {
    "object": {
      "type": "string",
      "const": "delivery_attempt",
      "description": "Always `delivery_attempt`."
    },
    "id": {
      "type": "string",
      "description": "The delivery service's identifier for this attempt. Opaque, and not\na UUID: it is minted on the other side of the handover.\n"
    },
    "newsletter": {
      "description": "The newsletter whose event this was. A `Ref` unless `newsletter` is\nnamed in `?expand=`.\n",
      "oneOf": [
        {
          "$ref": "#/$defs/Ref"
        },
        {
          "$ref": "#/$defs/Newsletter"
        }
      ]
    },
    "destination": {
      "allOf": [
        {
          "$ref": "#/$defs/Ref"
        }
      ],
      "description": "Where this was delivered. Always a `Ref`, whose `id` matches a row\nfrom `GET /newsletters/{newsletter}/destinations`. A destination\ndeleted since the attempt was made still appears here, because the\nattempt happened; it will not be in that list any more.\n"
    },
    "destination_type": {
      "type": "string",
      "description": "What kind of target it was, as the delivery service named it at the\ntime. Free text for the same reason `Destination.type` is: the\nvocabulary belongs to the delivery service and grows there.\n"
    },
    "event_id": {
      "type": "string",
      "description": "The event that was being delivered, by the `id` on its envelope.\nThe same string the consumer receives in the `Commune-Event-Id`\nheader, which makes it the one identifier both sides share and the\nthing worth logging on yours.\n"
    },
    "event_type": {
      "type": [
        "string",
        "null"
      ],
      "description": "The topic, matching the keys of the `webhooks` block of this\ndocument. Null only if the delivery service no longer holds the\nevent this attempt belonged to.\n"
    },
    "status": {
      "allOf": [
        {
          "$ref": "#/$defs/DeliveryAttemptStatus"
        }
      ],
      "description": "How this attempt ended."
    },
    "response_status": {
      "type": [
        "integer",
        "null"
      ],
      "description": "The HTTP status the destination answered with. Null when it did not\nanswer at all, in which case `failure` says why.\n"
    },
    "failure": {
      "type": [
        "string",
        "null"
      ],
      "description": "Why there was no answer, when there was none: `timeout` is the\ncommon one. Null whenever `response_status` is set, and the two are\nnever both set or both null. Free text, so treat an unrecognised\nvalue as a reason this client does not know how to describe.\n"
    },
    "attempt": {
      "type": "integer",
      "minimum": 1,
      "description": "1 on the first delivery of this event to this destination, and one\nhigher on each retry of it. The number the\n`Commune-Delivery-Attempt` header would carry if it were sent.\n"
    },
    "manual": {
      "type": "boolean",
      "description": "Whether somebody asked for this attempt rather than the delivery\nservice making it on its own. True for one made by\n`POST /delivery-attempts/{attempt}/replay` or by the retry button in\nthe portal, and false for a first delivery or an automatic retry.\n"
    },
    "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the attempt was made."
    }
  },
  "$defs": {
    "Article": {
      "type": "object",
      "title": "Article",
      "description": "One article of a newsletter, without its body. Every collection of\narticles returns this shape. `GET /articles/{article}` returns\n`ArticleWithContent`, which is this plus `content`.\n",
      "required": [
        "object",
        "id",
        "short_id",
        "slug",
        "newsletter",
        "status",
        "is_imported",
        "created_at"
      ],
      "properties": {
        "object": {
          "type": "string",
          "const": "article",
          "description": "Always `article`."
        },
        "id": {
          "type": "string",
          "format": "uuid",
          "description": "Stable identifier."
        },
        "short_id": {
          "type": "string",
          "description": "Eight character base62 identifier, unique across Commune. Safe in a\nURL and accepted anywhere `{article}` is.\n"
        },
        "slug": {
          "type": "string",
          "description": "URL segment under the newsletter, unique within it but not across\nCommune. The permalink is `/n/{handle}/a/{slug}`. Falls back to the\n`short_id` for an untitled article.\n"
        },
        "newsletter": {
          "description": "The newsletter this article belongs to. A `Ref` unless `newsletter` is\nnamed in `?expand=`.\n",
          "oneOf": [
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/Newsletter"
            }
          ]
        },
        "title": {
          "type": [
            "string",
            "null"
          ],
          "description": "Subject line of the article. Null for an untitled draft."
        },
        "preview_text": {
          "type": [
            "string",
            "null"
          ],
          "description": "The short line email clients show after the subject, and what\nCommune uses as the excerpt on a card.\n"
        },
        "image_url": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "Cover image. When the creator set none, Commune stamps the first\nimage in the body at send time, so this is usually populated for a\nsent article.\n"
        },
        "external_url": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "The article's canonical URL on the newsletter's own provider, for an\nimported article. Null for one written in Commune.\n"
        },
        "status": {
          "$ref": "#/$defs/ArticleStatus"
        },
        "is_imported": {
          "type": "boolean",
          "description": "`true` when the article came in from the newsletter's provider,\n`false` when it was written and sent in Commune.\n"
        },
        "posted_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time",
          "description": "When the article went out. An article dated in the future is not\nreturned by any read operation until that moment passes, so this is\nnever ahead of now in a response.\n"
        },
        "scheduled_for": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time",
          "description": "When a queued article may go out. Set while `status` is `scheduled`\nand null otherwise.\n\nThis is not `posted_at` and the difference matters: a queued article\nhas no publication date yet, which is why it stays invisible on\nevery reader surface until it really goes out. Commune dispatches\nin passes, so this is the moment from which the article may go rather\nthan the moment it will.\n"
        },
        "authors": {
          "type": "array",
          "description": "The byline, in order. Each entry is a `Ref` unless `authors` is\nnamed in `?expand=`. Empty when no Commune account is credited.\n",
          "items": {
            "anyOf": [
              {
                "$ref": "#/$defs/Ref"
              },
              {
                "$ref": "#/$defs/User"
              }
            ]
          }
        },
        "thread": {
          "description": "The chat thread this article opened, where its discussion lives.\n`null` when the newsletter does not open a thread per article. A `Ref`\nunless `thread` is named in `?expand=`.\n",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/Thread"
            }
          ]
        },
        "stats": {
          "$ref": "#/$defs/ArticleStats"
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the row was created in Commune."
        },
        "updated_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the article was last edited."
        }
      }
    },
    "ArticleStats": {
      "type": "object",
      "title": "ArticleStats",
      "description": "Engagement counts for an article, computed at read time. These are\nCommune side counts, not provider side email metrics: opens, clicks and\ndeliveries are not here.\n",
      "additionalProperties": false,
      "required": [
        "likes",
        "comments",
        "highlights"
      ],
      "properties": {
        "likes": {
          "type": "integer",
          "minimum": 0,
          "description": "How many people liked the article."
        },
        "comments": {
          "type": "integer",
          "minimum": 0,
          "description": "Replies in the article's chat thread. Commune has no separate\ncomments store: an article's discussion is a thread like any other,\nso this counts the undeleted replies hanging off it. `0` when the\narticle has no thread.\n"
        },
        "highlights": {
          "type": "integer",
          "minimum": 0,
          "description": "How many passages readers highlighted."
        }
      }
    },
    "ArticleStatus": {
      "type": "string",
      "title": "ArticleStatus",
      "description": "Where an article is in its life. A credential holding only `read`\npermissions ever sees `sent` and nothing else. An imported article is\nalways `sent`, since Commune sees it after the provider delivered it.\n",
      "enum": [
        "draft",
        "scheduled",
        "sending",
        "sent",
        "failed",
        "archived"
      ]
    },
    "DeliveryAttemptStatus": {
      "type": "string",
      "title": "DeliveryAttemptStatus",
      "description": "How one attempt ended. `succeeded` is a 2xx from the destination.\n`failed` is anything else, including no answer at all, and is not\nfinal: the delivery service retries on its own.\n",
      "enum": [
        "succeeded",
        "failed"
      ]
    },
    "Esp": {
      "type": "string",
      "title": "Esp",
      "description": "Where a newsletter is published from. `commune` means Commune itself\nsends the email. Every other value is an email service provider whose\nposts Commune imports. `rss` covers any feed that is not one of the\nnamed providers.\n",
      "enum": [
        "commune",
        "beehiiv",
        "buttondown",
        "ghost",
        "kit",
        "mailchimp",
        "mailerlite",
        "rss",
        "substack"
      ]
    },
    "Media": {
      "type": "object",
      "title": "Media",
      "description": "An image or file attached to a thread or a message.",
      "additionalProperties": false,
      "required": [
        "url"
      ],
      "properties": {
        "url": {
          "type": "string",
          "format": "uri",
          "description": "Where the attachment is served from."
        },
        "type": {
          "type": [
            "string",
            "null"
          ],
          "description": "The attachment's media type when Commune recorded one, for example\n`image/png`. Null for an attachment old enough that none was\nrecorded.\n"
        },
        "thumbnail": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "A smaller rendition, when one was generated."
        }
      }
    },
    "Newsletter": {
      "type": "object",
      "title": "Newsletter",
      "description": "A newsletter and its public profile. Nothing operational is exposed:\nESP credentials, OAuth tokens, group and audience ids, feed polling\nstate and language detection bookkeeping all stay server side.\n",
      "additionalProperties": false,
      "required": [
        "object",
        "id",
        "handle",
        "name",
        "esp",
        "created_at"
      ],
      "properties": {
        "object": {
          "type": "string",
          "const": "newsletter",
          "description": "Always `newsletter`."
        },
        "id": {
          "type": "string",
          "format": "uuid",
          "description": "Stable identifier."
        },
        "handle": {
          "type": "string",
          "description": "The short, unique, URL safe name. Resolves the public profile at\n`/n/{handle}` and is accepted anywhere `{newsletter}` is.\n"
        },
        "name": {
          "type": "string",
          "description": "Display name, as the creator writes it."
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "The profile blurb. Sanitised HTML, not plain text, because creators\nformat it. Treat it as untrusted markup and render it in a\nsandboxed context.\n"
        },
        "esp": {
          "$ref": "#/$defs/Esp"
        },
        "image_url": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "Square avatar for the newsletter."
        },
        "website_url": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "The creator's own site, if they linked one."
        },
        "social_links": {
          "$ref": "#/$defs/SocialLinks"
        },
        "language": {
          "type": [
            "string",
            "null"
          ],
          "description": "Best known language of the newsletter's writing as a BCP 47 tag.\nDetected from recent articles rather than declared, so treat it as a\nhint. Null before enough has been published to tell.\n"
        },
        "chat_create_permission": {
          "type": "string",
          "enum": [
            "editors",
            "subscribers",
            "anyone"
          ],
          "description": "Who may start a new chat thread in this community.\n"
        },
        "allow_non_subscriber_chat": {
          "type": "boolean",
          "description": "Whether people who have not subscribed may reply in existing\nthreads.\n"
        },
        "owner": {
          "description": "The account that owns the newsletter. A `Ref` unless `owner` is\nnamed in `?expand=`.\n",
          "anyOf": [
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/User"
            }
          ]
        },
        "featured_article": {
          "description": "The article the creator pinned to the top of the profile, or `null`\nwhen none is pinned. A `Ref` unless `featured_article` is named in\n`?expand=`.\n",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/Article"
            }
          ]
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the newsletter was connected to or created on Commune."
        },
        "updated_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the profile last changed."
        }
      }
    },
    "Ref": {
      "type": "object",
      "title": "Ref",
      "description": "An unexpanded relationship. Ask for the relationship in `?expand=` to\nget the full object in its place.\n",
      "additionalProperties": false,
      "required": [
        "object",
        "id"
      ],
      "properties": {
        "object": {
          "type": "string",
          "description": "The type of the referenced resource."
        },
        "id": {
          "type": "string",
          "description": "The referenced resource's `id`, in whatever form that resource's own\nschema declares. Most are UUIDs; a `Ref` whose `object` is `user`\ncarries an account identifier, which is an opaque string and not a\nUUID. Compare it for equality and pass it back; do not parse it.\n"
        }
      }
    },
    "SocialLinks": {
      "type": "object",
      "title": "SocialLinks",
      "description": "The creator's other homes on the internet, stored as canonical profile\nURLs. Every key is optional and a newsletter that set none returns an\nempty object.\n",
      "additionalProperties": false,
      "properties": {
        "twitter": {
          "type": "string",
          "format": "uri",
          "description": "X or Twitter profile URL."
        },
        "bluesky": {
          "type": "string",
          "format": "uri",
          "description": "Bluesky profile URL."
        },
        "linkedin": {
          "type": "string",
          "format": "uri",
          "description": "LinkedIn profile URL."
        },
        "mastodon": {
          "type": "string",
          "format": "uri",
          "description": "Mastodon profile URL, including the instance host."
        },
        "youtube": {
          "type": "string",
          "format": "uri",
          "description": "YouTube channel URL."
        },
        "instagram": {
          "type": "string",
          "format": "uri",
          "description": "Instagram profile URL."
        },
        "threads": {
          "type": "string",
          "format": "uri",
          "description": "Threads profile URL."
        },
        "github": {
          "type": "string",
          "format": "uri",
          "description": "GitHub profile URL."
        }
      }
    },
    "Thread": {
      "type": "object",
      "title": "Thread",
      "description": "A conversation in a newsletter's community, together with the message\nthat opened it. Its replies are a separate collection.\n",
      "additionalProperties": false,
      "required": [
        "object",
        "id",
        "newsletter",
        "content",
        "visibility",
        "is_article_thread",
        "created_at",
        "last_activity_at"
      ],
      "properties": {
        "object": {
          "type": "string",
          "const": "thread",
          "description": "Always `thread`."
        },
        "id": {
          "type": "string",
          "format": "uuid",
          "description": "Stable identifier."
        },
        "short_id": {
          "type": [
            "string",
            "null"
          ],
          "description": "Eight character base62 identifier used by the thread's own URL at\n`/n/{handle}/chat/{short_id}`. Null for a thread Commune opened\nunder an article, which is reached through the article instead.\n"
        },
        "newsletter": {
          "description": "The community this thread lives in. A `Ref` unless `newsletter` is\nnamed in `?expand=`.\n",
          "oneOf": [
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/Newsletter"
            }
          ]
        },
        "author": {
          "description": "Who opened the thread. A `Ref` unless `author` is named in\n`?expand=`.\n",
          "anyOf": [
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/User"
            }
          ]
        },
        "content": {
          "type": "string",
          "description": "The opening message. HTML, since people format what they write.\nTreat it as untrusted markup and render it in a sandboxed context.\n"
        },
        "media": {
          "type": "array",
          "description": "Attachments on the opening message.",
          "items": {
            "$ref": "#/$defs/Media"
          }
        },
        "visibility": {
          "$ref": "#/$defs/ThreadVisibility"
        },
        "is_article_thread": {
          "type": "boolean",
          "description": "`true` when Commune opened this thread under an article rather than\na person starting it. These are kept off the global feed, because\nthe article card already represents the conversation there.\n"
        },
        "article": {
          "description": "The article that opened this thread, when `is_article_thread` is\n`true`. `null` otherwise. A `Ref` unless `article` is named in\n`?expand=`.\n",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/Ref"
            },
            {
              "$ref": "#/$defs/Article"
            }
          ]
        },
        "reply_count": {
          "type": "integer",
          "minimum": 0,
          "description": "Undeleted replies in the thread, at any depth."
        },
        "view_count": {
          "type": "integer",
          "minimum": 0,
          "description": "How many times the thread was opened."
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the thread was opened."
        },
        "updated_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the thread row last changed for any reason."
        },
        "edited_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time",
          "description": "When the author last edited the opening message. Null when it was\nnever edited, which is what drives the edited marker in the product.\n"
        },
        "last_activity_at": {
          "type": "string",
          "format": "date-time",
          "description": "When the thread last received a reply, or when it was opened if it\nnever did. This is the sort key for the thread list.\n"
        }
      }
    },
    "ThreadVisibility": {
      "type": "string",
      "title": "ThreadVisibility",
      "description": "Where a thread is placed. `public` puts it on the global Commune feed\nand makes it readable by anyone. `subscribers` keeps it inside the\nnewsletter. `paid` narrows it further to the paying part of the\naudience. Set and changed by the newsletter's team.\n",
      "enum": [
        "public",
        "subscribers",
        "paid"
      ]
    },
    "User": {
      "type": "object",
      "title": "User",
      "description": "A person's public profile, and the whole of what this API returns about\nanybody other than the credential's own owner. Email address, theme,\nnotification preferences, push subscriptions, read state and saved\narticles are never carried.\n",
      "additionalProperties": false,
      "required": [
        "object",
        "id"
      ],
      "properties": {
        "object": {
          "type": "string",
          "const": "user",
          "description": "Always `user`."
        },
        "id": {
          "type": "string",
          "description": "Stable identifier."
        },
        "username": {
          "type": [
            "string",
            "null"
          ],
          "description": "The unique handle the profile resolves on at `/@{username}`. Null\nfor an account that has not finished signing up.\n"
        },
        "display_name": {
          "type": [
            "string",
            "null"
          ],
          "description": "The name shown next to their messages and bylines."
        },
        "avatar": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "Profile picture. Commune falls back to a generated avatar when the\nperson never set one, so this is rarely null in practice.\n"
        }
      }
    }
  }
}

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/usecommune-delivery-attempt"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.