Buttondown External Feeds API

The External Feeds API from Buttondown — 7 operation(s) covering RSS-to-email feeds, their polling cadence and the items they produce.

OpenAPI Specification

buttondown-external-feeds-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Buttondown External Feeds API
  version: 1.0.0
  description: The Buttondown API lets you manage newsletters, subscribers, emails, and more. See [the documentation](https://docs.buttondown.com/api-introduction)
    for guides and examples.
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
- url: https://api.buttondown.com/v1
security:
- ApiKeyAuth: []
tags:
- name: External Feeds
paths:
  /external_feeds:
    post:
      operationId: create_external_feed
      summary: Create External Feed
      parameters: []
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalFeed'
          links:
            retrieve_external_feed:
              operationId: retrieve_external_feed
              parameters:
                path.id: $response.body#/id
            update_external_feed:
              operationId: update_external_feed
              parameters:
                path.id: $response.body#/id
            delete_external_feed:
              operationId: delete_external_feed
              parameters:
                path.id: $response.body#/id
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '422':
          description: Unprocessable Entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorMessage'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Create a new external feed
      tags:
      - External Feeds
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalFeedInput'
        required: true
      security:
      - ApiKeyAuth: []
    get:
      operationId: list_external_feed
      summary: List External Feed
      parameters:
      - in: query
        name: page
        required: false
        description: The page number of the paginated response.
        schema:
          type: integer
          title: Page
          description: The page number of the paginated response.
          default: 1
          example: 1
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalFeedPage'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: List all external feeds
      tags:
      - External Feeds
      security:
      - ApiKeyAuth: []
  /external_feeds/{id}:
    patch:
      operationId: update_external_feed
      summary: Update External Feed
      parameters:
      - in: path
        name: id
        schema:
          title: Id
          type: string
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalFeed'
          links:
            retrieve_external_feed:
              operationId: retrieve_external_feed
              parameters:
                path.id: $response.body#/id
            delete_external_feed:
              operationId: delete_external_feed
              parameters:
                path.id: $response.body#/id
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '422':
          description: Unprocessable Entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorMessage'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Update an external feed's properties
      tags:
      - External Feeds
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalFeedUpdateInput'
        required: true
      security:
      - ApiKeyAuth: []
    delete:
      operationId: delete_external_feed
      summary: Delete External Feed
      parameters:
      - in: path
        name: id
        schema:
          title: Id
          type: string
        required: true
      responses:
        '204':
          description: No Content
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Delete an external feed
      tags:
      - External Feeds
      security:
      - ApiKeyAuth: []
    get:
      operationId: retrieve_external_feed
      summary: Retrieve External Feed
      parameters:
      - in: path
        name: id
        schema:
          title: Id
          type: string
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalFeed'
          links:
            update_external_feed:
              operationId: update_external_feed
              parameters:
                path.id: $response.body#/id
            delete_external_feed:
              operationId: delete_external_feed
              parameters:
                path.id: $response.body#/id
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Retrieve a specific external feed by its ID
      tags:
      - External Feeds
      security:
      - ApiKeyAuth: []
  /external_feeds/{id}/items:
    post:
      operationId: poll_items
      summary: Poll Items
      parameters:
      - in: path
        name: id
        schema:
          title: Id
          type: string
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Empty'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Poll for new items in an external feed
      tags:
      - External Feeds
      security:
      - ApiKeyAuth: []
    get:
      operationId: retrieve_items
      summary: Retrieve Items
      parameters:
      - in: path
        name: id
        schema:
          title: Id
          type: string
        required: true
      - in: query
        name: expand
        schema:
          description: If provided, expand the given field.
          items:
            const: email
            type: string
          title: Expand
          type: array
        required: false
        description: If provided, expand the given field.
      - in: query
        name: page
        required: false
        description: The page number of the paginated response.
        schema:
          type: integer
          title: Page
          description: The page number of the paginated response.
          default: 1
          example: 1
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalFeedItemPage'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '409':
          description: Conflict
        '422':
          description: Unprocessable Entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorMessage'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
        '429':
          description: Too Many Requests
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests permitted per minute.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp at which the window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorMessage'
      description: Retrieve items from an external feed
      tags:
      - External Feeds
      security:
      - ApiKeyAuth: []
components:
  schemas:
    Analytics:
      properties:
        recipients:
          default: 0
          description: The number of subscribers the email was dispatched to.
          title: Recipients
          type: integer
        deliveries:
          default: 0
          description: The number of successful deliveries (recipients minus failures).
          title: Deliveries
          type: integer
        opens:
          default: 0
          description: The number of unique opens recorded.
          title: Opens
          type: integer
        clicks:
          default: 0
          description: The number of unique link clicks recorded.
          title: Clicks
          type: integer
        temporary_failures:
          default: 0
          description: The number of temporary delivery failures (e.g. soft bounces).
          title: Temporary Failures
          type: integer
        permanent_failures:
          default: 0
          description: The number of permanent delivery failures (e.g. hard bounces).
          title: Permanent Failures
          type: integer
        unsubscriptions:
          default: 0
          description: The number of subscribers who unsubscribed after receiving this email.
          title: Unsubscriptions
          type: integer
        complaints:
          default: 0
          description: The number of spam complaints recorded against this email.
          title: Complaints
          type: integer
        survey_responses:
          default: 0
          description: The number of survey responses submitted from this email.
          title: Survey Responses
          type: integer
        webmentions:
          default: 0
          description: The number of inbound webmentions received for this email.
          title: Webmentions
          type: integer
        page_views_lifetime:
          default: 0
          description: The total number of archive page views for this email since publication.
          title: Page Views Lifetime
          type: integer
        page_views_30:
          default: 0
          description: The number of archive page views in the last 30 days.
          title: Page Views 30
          type: integer
        page_views_7:
          default: 0
          description: The number of archive page views in the last 7 days.
          title: Page Views 7
          type: integer
        subscriptions:
          default: 0
          description: The number of new subscribers attributed to this email.
          title: Subscriptions
          type: integer
        paid_subscriptions:
          default: 0
          description: The number of new paid subscribers attributed to this email.
          title: Paid Subscriptions
          type: integer
        replies:
          default: 0
          description: The number of reply emails received from subscribers.
          title: Replies
          type: integer
        comments:
          default: 0
          description: The number of comments posted on this email.
          title: Comments
          type: integer
        social_mentions:
          default: 0
          description: The number of social media mentions of this email.
          title: Social Mentions
          type: integer
        temporary_failure_breakdown:
          description: Breakdown of temporary failures by reason code, sorted by count descending.
          items:
            $ref: '#/components/schemas/FailureBreakdownItem'
          title: Temporary Failure Breakdown
          type: array
        permanent_failure_breakdown:
          description: Breakdown of permanent failures by reason code, sorted by count descending.
          items:
            $ref: '#/components/schemas/FailureBreakdownItem'
          title: Permanent Failure Breakdown
          type: array
      title: Analytics
      type: object
    ArchivalMode:
      description: 'Governs who can view this email in the archive.


        `ARCHIVE_ONLY` is the odd one out: the email is publicly archived but

        is not email content at all (e.g. an imported blog post), so it is

        excluded from email-rendering contexts like "recent issues" widgets.'
      enum:
      - archive_only
      - disabled
      - enabled
      - enabled_for_paid_subscribers
      - enabled_for_subscribers
      title: ArchivalMode
      type: string
    CadenceMetadata:
      additionalProperties: false
      properties:
        time:
          anyOf:
          - pattern: ^([01]?[0-9]|2[0-3])$
            type: string
          - type: 'null'
          description: Hour of the day (0-23, as a string) when emails should be generated.
          title: Time
          example: '9'
        weekday:
          anyOf:
          - enum:
            - monday
            - tuesday
            - wednesday
            - thursday
            - friday
            - saturday
            - sunday
            type: string
          - type: 'null'
          description: Day of the week when emails should be generated. Required when cadence is `weekly`.
          title: Weekday
        monthday:
          anyOf:
          - enum:
            - monday
            - tuesday
            - wednesday
            - thursday
            - friday
            - saturday
            - sunday
            - firstday
            - lastday
            type: string
          - pattern: ^([1-9]|[12][0-9]|3[01])$
            type: string
          - type: 'null'
          description: Day of the month when emails should be generated. Accepts a numeric day (`1`-`31`, clamped to the last
            day for shorter months), a weekday name (first such day of the month), `firstday`, or `lastday`. Required when
            cadence is `monthly`.
          title: Monthday
      title: CadenceMetadata
      type: object
    Callout:
      description: 'Surfacing-time flags about an email that the UI uses to render contextual

        callouts (e.g. in the analytics panel). Computed on read; not persisted.'
      enum:
      - first_send_on_sending_domain
      title: Callout
      type: string
    Email:
      description: 'Emails are why you''re here on Buttondown, right?

        Creating an email via the API is just like creating one in the interface;

        it will instantly trigger sending actual emails,

        based on the tags and email type you provide.


        Relevant changes to the schema:


        - [2024-08-15](https://docs.buttondown.com/api-changelog-2024-08-15): unshipped the `included_tags` and `excluded_tags`
        fields.

        - [2024-12-30](https://docs.buttondown.com/api-changelog-2024-12-30): unshipped the `is_comments_disabled` field,
        and replaced it with a more flexible `commenting_mode` field.

        - [2025-09-23](https://docs.buttondown.com/api-changelog-2025-09-23): increased the maximum length of the `subject`
        field from 1000 to 2000 characters.'
      properties:
        id:
          description: A unique TypeID associated with the object.
          title: Id
          type: string
        creation_date:
          description: The date and time at which the object was first created.
          format: date-time
          title: Creation Date
          type: string
        absolute_url:
          description: The canonical web URL of the email on the newsletter's archive.
          title: Absolute Url
          type: string
        analytics:
          anyOf:
          - $ref: '#/components/schemas/Analytics'
          - type: 'null'
          description: Aggregate analytics for the email. Null until the email has been sent.
        callouts:
          description: A list of callouts that apply to this email — surfaced in the UI alongside analytics to flag context
            the reader should know about (e.g., first send on a custom sending domain).
          items:
            $ref: '#/components/schemas/Callout'
          title: Callouts
          type: array
        attachments:
          anyOf:
          - items:
              type: string
            type: array
          - type: 'null'
          description: A list of attachment IDs present on the email. (See [Attachments](https://docs.buttondown.com/api-attachments-introduction)
            for more information.)
          title: Attachments
        body:
          description: 'The body of the email, in either HTML or markdown format. Buttondown attempts to intelligently detect
            the format of the body automatically, but you can also specify the format explicitly by prepending the text with
            the `buttondown-editor-mode` comment: `<!-- buttondown-editor-mode: fancy -->` or `<!-- buttondown-editor-mode:
            plaintext -->`.'
          title: Body
          type: string
        canonical_url:
          description: The URL of the original source of the content.
          title: Canonical Url
          type: string
        commenting_mode:
          $ref: '#/components/schemas/EmailCommentingMode'
          description: Controls whether subscribers can comment on this email.
        description:
          description: A human-readable description of the email, used for archives and SEO.
          title: Description
          type: string
        archival_mode:
          $ref: '#/components/schemas/ArchivalMode'
          description: Controls who can view this email in the archive.
        email_type:
          allOf:
          - $ref: '#/components/schemas/EmailType'
          default: public
          deprecated: true
          description: 'The type of email. Defaults to `PUBLIC`. Deprecated: this is a legacy single-axis view derived from
            `archival_mode` (archive visibility) and `filters` (audience); prefer setting those directly. Because it is derived,
            it does not always round-trip: writing it alongside an explicit `archival_mode` that disagrees will report the
            value implied by the two underlying fields, and writing a value that already matches the derived one is a no-op.'
        featured:
          description: Designated whether or not this email should be highlighted within the archives.
          title: Featured
          type: boolean
        filters:
          $ref: '#/components/schemas/FilterGroup'
          description: Tag-based filter rules determining which subscribers receive this email.
        image:
          description: A primary image URL used when previewing the email on the web or in other contexts.
          title: Image
          type: string
        metadata:
          additionalProperties: true
          default: {}
          description: A structured key-value blob that you can use to store arbitrary data on the object. Metadata can be
            nested — you can store objects and arrays within your metadata. (You can [read more about metadata.](https://docs.buttondown.com/metadata))
          title: Metadata
          type: object
        modification_date:
          description: The date and time at which the object was last modified.
          format: date-time
          title: Modification Date
          type: string
        publish_date:
          anyOf:
          - format: date-time
            type: string
          - type: 'null'
          description: The date and time at which the email should be published in the future (for scheduled emails), or the
            date and time at which the email was published (for sent emails).
          title: Publish Date
        related_email_ids:
          description: A list of email IDs that are related to this email. Related emails are shown at the bottom of the email
            and archive pages.
          items:
            type: string
          title: Related Email Ids
          type: array
        secondary_id:
          anyOf:
          - type: integer
          - type: 'null'
          description: 'An informal ''number'' for the email, used in some templates (''This was issue #123'').'
          title: Secondary Id
        should_trigger_pay_per_email_billing:
          description: Whether this email should trigger pay-per-email billing for paid subscribers. Use this to differentiate
            between free updates and premium newsletters.
          title: Should Trigger Pay Per Email Billing
          type: boolean
        slug:
          anyOf:
          - type: string
          - type: 'null'
          description: A short, human-readable identifier for the email, used in the archive URL.
          example: welcome-to-the-newsletter
          title: Slug
        source:
          $ref: '#/components/schemas/EmailSource'
          description: The source of the email.
          example: app
        status:
          $ref: '#/components/schemas/EmailStatus'
          description: The current status of the email.
          example: draft
        subject:
          description: The subject line for the email.
          maxLength: 2000
          title: Subject
          type: string
        suppression_reason:
          anyOf:
          - $ref: '#/components/schemas/EmailSuppressionReason'
          - type: 'null'
          description: If the email has been suppressed from sending, the reason why.
        template:
          anyOf:
          - $ref: '#/components/schemas/NewsletterEmailTemplate'
          - type: 'null'
          description: If present, this template overrides your newsletter's default email template.
      required:
      - id
      - creation_date
      - absolute_url
      - body
      - canonical_url
      - commenting_mode
      - description
      - archival_mode
      - featured
      - filters
      - image
      - modification_date
      - related_email_ids
      - should_trigger_pay_per_email_billing
      - source
      - status
      - subject
      title: Email
      type: object
    EmailCommentingMode:
      description: 'Governs who can comment on this email.


        This enum replaces the `is_comments_disabled` field, which has been deprecated. (Also note that this field may be
        superseded by newsletter-level settings; for instance, "enabled" is an invalid and inert value if the newsletter itself
        has comments disabled.)'
      enum:
      - disabled
      - enabled
      - enabled_for_paid_subscribers
      title: CommentingMode
      type: string
    EmailSource:
      description: 'Represents the original provenance of an email. This value is not exposed

        to subscribers, but does determine some behavior of the email (e.g. whether

        or not analytics can be calculated.)'
      enum:
      - api
      - import
      - app
      - external_feed
      - smtp
      title: Source
      type: string
    EmailStatus:
      description: 'Represents the state of an email.


        No action is required to move from one state or another; Buttondown

        internally handles the transitions, and exposing the status is for

        observability purposes only.'
      enum:
      - draft
      - managed_by_rss
      - about_to_send
      - scheduled
      - in_flight
      - paused
      - deleted
      - errored
      - sent
      - imported
      - throttled
      - resending
      - transactional
      - suppressed
      title: Status
      type: string
    EmailSuppressionReason:
      description: Represents the reason an email was suppressed.
      enum:
      - law_enforcement
      - internal_auditing
      title: SuppressionReason
      type: string
    EmailType:
      description: 'The legacy single-axis representation of an email''s audience and

        archive visibility. No longer stored: `filters` owns the audience

        axis and `archival_mode` owns the archive axis, and the deprecated

        API field is derived from those (see `email_type` below).'
      enum:
      - public
      - private
      - premium
      - free
      - churned
      - archival
      title: Type
      type: string
    Empty:
      properties: {}
      title: Empty
      type: object
    ErrorMessage:
      properties:
        code:
          description: The error code.
          title: Code
          type: string
     

# --- truncated at 32 KB (52 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/buttondown/refs/heads/main/openapi/buttondown-external-feeds-api-openapi.yml