beehiiv subpackage_posts API

The subpackage_posts API from beehiiv — 3 operation(s) for subpackage_posts.

OpenAPI Specification

beehiiv-subpackage-posts-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: API Reference subpackage_advertisement_opportunities subpackage_posts API
  version: 1.0.0
servers:
- url: https://api.beehiiv.com/v2
tags:
- name: subpackage_posts
paths:
  /publications/{publicationId}/posts:
    post:
      operationId: create
      summary: 'Create post <Badge intent="info" minimal outlined>OAuth Scope: posts:write</Badge>'
      description: "<Note title=\"Currently in beta\" icon=\"b\">\n  This feature is currently in beta, the API is subject to change, and available only to Enterprise users.<br/><br/>To inquire about Enterprise pricing,\n  please visit our <a href=\"https://www.beehiiv.com/enterprise\">Enterprise page</a>.\n</Note>\nCreate a post for a specific publication. For a detailed walkthrough including setup, testing workflows, and working with custom HTML and templates, see the <a href=\"https://www.beehiiv.com/support/article/36759164012439-using-the-send-api-and-create-post-endpoint\">Using the Send API and Create Post Endpoint</a> guide.\n\n## Content methods\n\nThere are three ways to provide content for a post. You must provide either `blocks` or `body_content`, but not both.\n\n### 1. Blocks\n\nUse the `blocks` field to build your post with structured content blocks such as paragraphs, images, headings, buttons, tables, and more. Each block has a `type` and its own set of properties. This method gives you fine-grained control over individual content elements and supports features like visual settings, visibility settings, and dynamic content targeting.\n\n### 2. Raw HTML (`body_content`)\n\nUse the `body_content` field to provide a single string of raw HTML. The HTML is wrapped in an `htmlSnippet` block internally. This is useful when you have pre-built HTML content or are migrating from another platform.\n\n### 3. HTML blocks within blocks\n\nUse `type: html` blocks inside the `blocks` array to embed raw HTML snippets alongside other structured blocks. This lets you mix structured content (paragraphs, images, etc.) with custom HTML where needed.\n\n## CSS and styling guardrails\n\nbeehiiv processes all HTML content through a sanitization pipeline. When using `body_content` or `html` blocks, be aware of the following:\n\n- **`<style>` tags are removed.** All `<style>` block elements are stripped during sanitization. Do not rely on embedded stylesheets.\n- **`<link>` tags are removed.** External stylesheet references are not allowed.\n- **Inline styles are preserved.** Styles applied directly to elements via the `style` attribute (e.g., `<div style=\"color: red;\">`) are kept intact.\n- **CSS classes have no effect.** While class attributes are not stripped, no corresponding stylesheets are loaded to apply them.\n- **beehiiv's email template wraps your content.** Your HTML is rendered inside beehiiv's email table structure, which applies its own layout and spacing. This may affect the appearance of your content.\n- **Use inline styles for all visual styling.** Since `<style>` and `<link>` tags are removed, inline styles on individual elements are the only reliable way to control appearance."
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsCreateResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                blocks:
                  type: array
                  items:
                    $ref: '#/components/schemas/type_posts:Block'
                  description: The structured content blocks that make up the post. Supports block types such as paragraph, image, heading, button, html, table, list, columns, and more. You can embed raw HTML snippets within blocks using the `html` block type. Either this field OR the `body_content` field must be provided.
                body_content:
                  type: string
                  description: The content of the post as a single raw HTML string. The HTML is wrapped in an `htmlSnippet` block internally. Note that `<style>` and `<link>` tags are removed during sanitization — use inline styles for all visual styling. Either this field OR the `blocks` field must be provided.
                title:
                  type: string
                  description: The title of the post.
                subtitle:
                  type: string
                  description: The subtitle of the post.
                post_template_id:
                  $ref: '#/components/schemas/type_ids:PostTemplateId'
                  description: The ID of the template to use for the post. If not provided, the default template will be used.
                status:
                  $ref: '#/components/schemas/type_posts:PostPublishStatus'
                  description: The status of the post. If not provided, the default (`confirmed`) value will be used and the post will either publish immediately (if no `scheduled_at` is provided) or at the `scheduled_at` time. **Deprecation notice:** The default will change to `draft` in a future release. Explicitly pass `confirmed` to preserve current auto-publish behavior.
                scheduled_at:
                  type: string
                  format: date-time
                  description: The time in which the post will be published. If not provided, the post will be published immediately unless `status` is set to `draft`. A draft post cannot be scheduled.
                custom_link_tracking_enabled:
                  type: boolean
                  description: If true, custom link tracking will be enabled for this post. If not provided, the default value will be used.
                email_capture_type_override:
                  $ref: '#/components/schemas/type_posts:PostEmailCaptureTypeOverride'
                  description: The email capture type to use for this post. If not provided, the default value will be used.
                override_scheduled_at:
                  type: string
                  format: date-time
                  description: If you wish to display a date other than the scheduled_at date in the email, you can provide a date here. This will not affect the actual publish date of the post.
                social_share:
                  $ref: '#/components/schemas/type_posts:PostSocialShare'
                  description: The social share type to use for this post. If not provided, the default value will be used.
                thumbnail_image_url:
                  type: string
                  description: The URL of the thumbnail image to use for the post. If not provided, the default value will be used.
                recipients:
                  $ref: '#/components/schemas/type_posts:PostRecipients'
                  description: The recipients to use for this post. If not provided, the default value will be used.
                email_settings:
                  $ref: '#/components/schemas/type_posts:PostEmailSettings'
                  description: The email settings to use for this post. If not provided, the default value will be used.
                web_settings:
                  $ref: '#/components/schemas/type_posts:PostWebSettings'
                  description: The web settings to use for this post. If not provided, the default value will be used.
                seo_settings:
                  $ref: '#/components/schemas/type_posts:PostMetadata'
                  description: The metadata to use for this post. If not provided, the default value will be used.
                content_tags:
                  type: array
                  items:
                    type: string
                  description: The content tags to use for this post. If not provided, the default value will be used.
                headers:
                  type: object
                  additionalProperties:
                    type: string
                  description: The headers to use for this post. If not provided, the default value will be used.
                custom_fields:
                  type: object
                  additionalProperties:
                    type: string
                  description: The custom fields to use for this post. If not provided, the default value will be used.
                newsletter_list_id:
                  type: string
                  description: The prefixed ID of the newsletter list to associate with this post. When provided, the post will only be sent to subscribers of this list. <Badge intent="warning" minimal outlined>Beta</Badge>
              required:
              - title
    get:
      operationId: index
      summary: 'List posts <Badge intent="info" minimal outlined>OAuth Scope: posts:read</Badge>'
      description: Retrieve all posts belonging to a specific publication
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: expand
        in: query
        description: Optionally expand the results by adding additional information. <br>`stats` - Adds statistics about the post(s). <br>`free_web_content` - Adds the web HTML rendered to a free reader. <br>`free_email_content` - Adds the email HTML rendered to a free reader. <br>`free_rss_content` - Adds the RSS feed HTML. <br>`premium_web_content` - Adds the web HTML rendered to a premium reader. <br>`premium_email_content` - Adds the email HTML rendered to a premium reader.
        required: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/type_posts:PostExpandField'
      - name: audience
        in: query
        description: Optionally filter the results by audience
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostAudienceFilter'
      - name: platform
        in: query
        description: Optionally filter the results by platform.<br>`web` - Posts only published to web.<br>`email` - Posts only published to email.<br>`both` - Posts published to email and web.<br>`all` - Does not restrict results by platform.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostPlatformFilter'
      - name: status
        in: query
        description: Optionally filter the results by the status of the post.<br>`draft` - not been scheduled.<br>`confirmed` - The post will be active after the `scheduled_at`.<br>`archived` - The post is no longer active.<br>`all` - Does not restrict results by status.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostStatusFilter'
      - name: content_tags[]
        in: query
        description: 'Optionally filter posts by content_tags. Adding a content tag will return any post with that content tag associated to it.<br><br><b>Example</b>: Filtering for `content_tags: ["sales","closing"]` will return results of posts that have *either* `sales` or `closing` content_tags.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: slugs[]
        in: query
        description: 'Optionally filter posts by their slugs. Adding a slug will return any post with that exact slug associated to it.<br><br><b>Example:</b> Filtering for `slugs: ["my-first-post","another-post"]` will return results of posts that have *either* `my-first-post` or `another-post` as their slug.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: authors[]
        in: query
        description: 'Optionally filter posts by their authors. Adding an author name will return any post with that author associated to it (case-insensitive).<br><br><b>Example:</b> Filtering for `authors: ["John Doe","Jane Smith"]` will return results of posts that have *either* John Doe or Jane Smith as authors.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: premium_tiers
        in: query
        description: 'Optionally filter posts by audience based on premium tiers.<br> This takes in an array of Display Names of the premium tiers.<br> It will also scope any expanded content output to the specified premium tiers.<br> Note: This is case insensitive.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: limit
        in: query
        description: A limit on the number of objects to be returned. The limit can range between 1 and 100, and the default is 10.
        required: false
        schema:
          type: integer
      - name: page
        in: query
        description: 'Pagination returns the results in pages. Each page contains the number of results specified by the `limit` (default: 10).<br>If not specified, results 1-10 from page 1 will be returned.'
        required: false
        schema:
          type: integer
      - name: order_by
        in: query
        description: The field that the results are sorted by. Defaults to created<br> `created` - The time in which the post was first created.<br> `publish_date` - The time the post was set to be published.<br> `displayed_date` - The time displayed in place of the `publish_date`. If no `displayed_date` was set, it will default to the `publish_date`
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostOrderBy'
      - name: direction
        in: query
        description: The direction that the results are sorted in. Defaults to asc<br> `asc` - Ascending, sorts from smallest to largest.<br> `desc` - Descending, sorts from largest to smallest.
        required: false
        schema:
          $ref: '#/components/schemas/type_:RequestDirection'
      - name: hidden_from_feed
        in: query
        description: Optionally filter the results by the `hidden_from_feed` attribute of the post.<br>`all` - Does not restrict results by `hidden_from_feed`.<br>`true` - Only return posts hidden from the feed.<br>`false` - Only return posts that are visible on the feed.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostsListRequestHiddenFromFeed'
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsListResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
  /publications/{publicationId}/posts/{postId}:
    patch:
      operationId: update
      summary: 'Update post <Badge intent="info" minimal outlined>OAuth Scope: posts:write</Badge>'
      description: "<Note title=\"Currently in beta\" icon=\"b\">\n  This feature is currently in beta, the API is subject to change, and available only to Enterprise users.<br/><br/>To inquire about Enterprise pricing,\n  please visit our <a href=\"https://www.beehiiv.com/enterprise\">Enterprise page</a>.\n</Note>\nUpdate an existing post for a specific publication. Only the fields provided in the request body will be updated — all other fields remain unchanged. For a detailed walkthrough of content methods and working with custom HTML, see the <a href=\"https://www.beehiiv.com/support/article/36759164012439-using-the-send-api-and-create-post-endpoint\">Using the Send API and Create Post Endpoint</a> guide.\n\nTo update post content, provide either `blocks` or `body_content` (not both). If neither is provided, the existing content is preserved. The same content methods and CSS guardrails described in the create endpoint apply here."
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: postId
        in: path
        description: The prefixed ID of the post to update
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PostId'
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsGetResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                blocks:
                  type: array
                  items:
                    $ref: '#/components/schemas/type_posts:Block'
                  description: The structured content blocks to replace the post's current content. Supports block types such as paragraph, image, heading, button, html, table, list, columns, and more. Cannot be provided together with `body_content`.
                body_content:
                  type: string
                  description: Raw HTML to replace the post's current content. The HTML is wrapped in an `htmlSnippet` block internally. Note that `<style>` and `<link>` tags are removed during sanitization — use inline styles for all visual styling. Cannot be provided together with `blocks`.
                title:
                  type: string
                  description: The title of the post.
                subtitle:
                  type: string
                  description: The subtitle of the post.
                scheduled_at:
                  type: string
                  format: date-time
                  description: The time at which the post will be published. Cannot be updated after the post has already been sent.
                custom_link_tracking_enabled:
                  type: boolean
                  description: If true, custom link tracking will be enabled for this post.
                email_capture_type_override:
                  $ref: '#/components/schemas/type_posts:PostEmailCaptureTypeOverride'
                  description: The email capture type to use for this post.
                override_scheduled_at:
                  type: string
                  format: date-time
                  description: A display date that overrides the scheduled_at date shown in the email. Does not affect the actual publish date.
                social_share:
                  $ref: '#/components/schemas/type_posts:PostSocialShare'
                  description: The social share type to use for this post.
                thumbnail_image_url:
                  type: string
                  description: The URL of the thumbnail image to use for the post.
                email_settings:
                  $ref: '#/components/schemas/type_posts:PostEmailSettings'
                  description: The email settings to use for this post. Only the provided fields within this object will be updated.
                web_settings:
                  $ref: '#/components/schemas/type_posts:PostWebSettings'
                  description: The web settings to use for this post. Only the provided fields within this object will be updated.
                seo_settings:
                  $ref: '#/components/schemas/type_posts:PostMetadata'
                  description: The SEO metadata to use for this post. Only the provided fields within this object will be updated.
                content_tags:
                  type: array
                  items:
                    type: string
                  description: The content tags for this post. When provided, this replaces all existing content tags on the post.
    get:
      operationId: show
      summary: 'Get post <Badge intent="info" minimal outlined>OAuth Scope: posts:read</Badge>'
      description: Retrieve a single Post belonging to a specific publication
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: postId
        in: path
        description: The prefixed ID of the post object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PostId'
      - name: expand
        in: query
        description: Optionally expand the results by adding additional information. <br>`stats` - Adds statistics about the post(s). <br>`free_web_content` - Adds the web HTML rendered to a free reader. <br>`free_email_content` - Adds the email HTML rendered to a free reader. <br>`free_rss_content` - Adds the RSS feed HTML. <br>`premium_web_content` - Adds the web HTML rendered to a premium reader. <br>`premium_email_content` - Adds the email HTML rendered to a premium reader.
        required: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/type_posts:PostExpandField'
      - name: premium_tiers
        in: query
        description: 'Scope any expanded content output to the specified premium tiers.<br> This takes in an array of Display Names of the premium tiers.<br> Note: This is case insensitive.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsGetResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
    delete:
      operationId: delete
      summary: 'Delete post <Badge intent="info" minimal outlined>OAuth Scope: posts:write</Badge>'
      description: Delete or Archive a post. Any post that has been confirmed will have it's status changed to `archived`. Posts in the `draft` status will be permanently deleted.
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: postId
        in: path
        description: The prefixed ID of the post object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PostId'
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '204':
          description: No Content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsDeleteResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
  /publications/{publicationId}/posts/aggregate_stats:
    get:
      operationId: aggregate-stats
      summary: 'Get aggregate stats <Badge intent="info" minimal outlined>OAuth Scope: posts:read</Badge>'
      description: Retrieve aggregate stats for all posts
      tags:
      - subpackage_posts
      parameters:
      - name: publicationId
        in: path
        description: The prefixed ID of the publication object
        required: true
        schema:
          $ref: '#/components/schemas/type_ids:PublicationId'
      - name: audience
        in: query
        description: Optionally filter the results by audience
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostAudienceFilter'
      - name: platform
        in: query
        description: Optionally filter the results by platform.<br>`web` - Posts only published to web.<br>`email` - Posts only published to email.<br>`both` - Posts published to email and web.<br>`all` - Does not restrict results by platform.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostPlatformFilter'
      - name: status
        in: query
        description: Optionally filter the results by the status of the post.<br>`draft` - not been scheduled.<br>`confirmed` - The post will be active after the `scheduled_at`.<br>`archived` - The post is no longer active.<br>`all` - Does not restrict results by status.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostStatusFilter'
      - name: content_tags[]
        in: query
        description: 'Optionally filter posts by content_tags. Adding a content tag will return any post with that content tag associated to it.<br>Example: Filtering for `content_tags: ["sales","closing"]` will return results of posts that have *either* sales or closing content_tags.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: authors[]
        in: query
        description: 'Optionally filter posts by their authors. Adding an author name will return any post with that author associated to it (case-insensitive).<br><br><b>Example:</b> Filtering for `authors: ["John Doe","Jane Smith"]` will return results of posts that have *either* John Doe or Jane Smith as authors.'
        required: false
        schema:
          type: array
          items:
            type: string
      - name: hidden_from_feed
        in: query
        description: Optionally filter the results by the `hidden_from_feed` attribute of the post.<br>`all` - Does not restrict results by `hidden_from_feed`.<br>`true` - Only return posts hidden from the feed.<br>`false` - Only return posts that are visible on the feed.
        required: false
        schema:
          $ref: '#/components/schemas/type_posts:PostsListRequestHiddenFromFeed'
      - name: Authorization
        in: header
        description: Bearer authentication
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_posts:PostsAggregateStatsResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '404':
          description: Resource Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '429':
          description: Rate Limit Exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/type_:Error'
components:
  schemas:
    type_posts:EmbeddableBlocks:
      oneOf:
      - type: object
        properties:
          type:
            type: string
            enum:
            - paragraph
            description: 'Discriminator value: paragraph'
          visual_settings:
            $ref: '#/components/schemas/type_posts:VisualSettings'
            description: Optional styling for borders, spacing, colors, etc.
          visibility_settings:
            $ref: '#/components/schemas/type_posts:VisibilitySettings'
            description: Optional rules for when/where this block is shown, including dynamic content targeting via condition sets.
          plaintext:
            type: string
            description: The plaintext content of th

# --- truncated at 32 KB (84 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/beehiiv/refs/heads/main/openapi/beehiiv-subpackage-posts-api-openapi.yml