Create post OAuth Scope: posts:write
Create post OAuth Scope: posts:write
This endpoint is available to publications on the Pro and Enterprise plans.
Create a post for a specific publication. For a detailed walkthrough including setup, testing workflows, and working with custom HTML and templates, see the Using the Send API and Create Post Endpoint guide.
Asynchronous creation
Post creation is processed in the background. This endpoint returns 201 immediately with the post’s id, but the post is not finished being created at that moment. The returned id is stable — it is the same id the post will have once creation completes.
If you fetch the post (GET /publications/{publicationId}/posts/{postId}) right away, it may not exist yet. In that case the fetch returns 202 (still being created) — wait briefly and retry, honoring the Retry-After header. If background creation fails, the fetch returns 404 with the error code POST_CREATION_FAILED, so you should stop retrying, verify your request, and try creating the post again.
Content methods
There are three ways to provide content for a post. You must provide either blocks or body_content, but not both.
1. Blocks
Use 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.
2. Raw HTML (body_content)
Use 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.
3. HTML blocks within blocks
Use 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.
CSS and styling guardrails
beehiiv processes all HTML content through a sanitization pipeline. When using body_content or html blocks, be aware of the following:
<style>tags are removed. All<style>block elements are stripped during sanitization. Do not rely on embedded stylesheets.<link>tags are removed. External stylesheet references are not allowed.- Inline styles are preserved. Styles applied directly to elements via the
styleattribute (e.g.,<div style="color: red;">) are kept intact. - CSS classes have no effect. While class attributes are not stripped, no corresponding stylesheets are loaded to apply them.
- 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.
- 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.
Authentication
Bearer authentication of the form Bearer <token>, where token is your auth token.
Path parameters
Request
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.
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.
The status of the post. If not provided, the default (draft) value will be used and the post will not be scheduled or published. Explicitly pass confirmed to have the post publish immediately (if no scheduled_at is provided) or at the scheduled_at time.
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.
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.
Custom email headers for this post. Merges with newsletter list and publication headers at send time, with this post’s values winning on a key collision. Set a value to null to suppress a header inherited from the newsletter list or publication. System-managed headers (e.g. List-Unsubscribe, X-SMTPAPI) cannot be overridden.
Additional custom CSS added to this post’s email <head>. Use this for styles, since <style> tags in body_content are removed. Applies to email only, not the web version. This replaces any custom CSS from the template the post is built from, while an empty string keeps the template’s CSS.
The utm_source appended to links in this post. Falls back to the newsletter list, then the publication, then a generated default.
The utm_medium appended to links in this post. Falls back to the newsletter list, then the publication, then a generated default.
The utm_campaign appended to links in this post. Falls back to the newsletter list, then the publication, then a generated default.