Using the Send API and Create post endpoint
paid plans
The Create post endpoint allows you to generate beehiiv posts programmatically using the same building blocks available inside the beehiiv UI. This guide explains the core concepts you’ll need to understand before making calls to the Send API, including setup requirements, content options, styling rules, and examples.
For full technical specifications, refer to our developer documentation.
How the beehiiv Send API works
Our Send API uses the Create post endpoint to mirror the structure of the beehiiv Post Builder. Instead of sending raw HTML emails, your API request triggers the same widgets and blocks used when composing a post in the UI.
This approach ensures API-generated emails can still use:
- Ad Network placements
- Buttons
- HTML snippets
- Image blocks
- Polls
- And all other supported content blocks
The beehiiv email structure is fixed. Although you can add custom HTML and CSS, you cannot replace the or standard footer elements required for CAN-SPAM/GDPR compliance. Additionally, we do not currently offer the ability to send 100% custom HTML email.
Email template constraints
Every beehiiv post, whether created manually or via API, uses fixed HTML content, including:
- Email <head> (not editable)
- Required footer (not removable)
However, you can add custom CSS or HTML to each template from the Post Builder via:
- Style > Advanced > Email Header > Code
- Style > Advanced > Email Footer > Custom
Refer to these articles for more information on using the Style panel and customizing your newsletter footer.
Setup requirements and testing
You can test your API calls via the command-line tester built into beehiiv’s API reference or with external API testing tools such as Postman, Insomnia, etc.
Credentials you’ll need:
- Your publication ID
- Auth type: Bearer token
- Token
- POST: https://api.beehiiv.com/v2/publications/[:publication_Id]/posts
Minimum request objects:
- title
- blocks or body_content
The above minimum request objects will create a post that publishes immediately with your default template to all free subscribers. Starting August 6, 2026, this behavior requires explicitly passing "status": "confirmed" in your request. For a full list of request objects available, see our API reference.
Upcoming change: default status will switch to draft on 8/6/26
What's changing: Starting August 6, 2026, a Create post API call made without a status parameter will default to draft instead of publishing automatically. This update is designed to prevent accidental publishes.
Are you affected? If your API calls already pass "status": "confirmed" explicitly, nothing changes for you. If any of your calls omit status, you'll need to add it before August 6, 2026 to keep those posts publishing (or sending at their scheduled time) automatically:
json
{
"status": "confirmed"
}
This also affects scheduled posts. Currently, if status is omitted and scheduled_at is provided, the post is published at the scheduled time. Once the default changes, an omitted status will result in a draft regardless of any scheduled_at value, so scheduled sends that rely on the omitted-status default will also need status: "confirmed" added.
You may already notice an X-Beehiiv-Deprecation response header on Send API calls that don't include status. This header is an early, automated reminder of this change and doesn't indicate an error with your request.
Post body content and templates
The Create post endpoint allows you to populate the body of a post via two different requests (only one must be chosen):
- Using blocks: A series of widgets identical to what’s available in the beehiiv UI.
- Using body_content: The entire body of the email is populated by custom HTML.
Additional block notes:
- Not every UI block is available yet, please refer to our developer docs for the supported list.
- It is not possible to inject feature blocks (ads, polls, etc.) into the HTML of a body_content request.
- To use your own custom HTML, we recommend using the blocks request and mixing beehiiv’s blocks with your HTML via the html block request. This will preserve the ability to blend the benefits of our feature blocks with your custom HTML in any order required.
Style: templates
The post_template_id request allows you to merge the style of an existing template in your beehiiv publication with the content of your incoming Create post call (blocks / body_content).
For the template requested, incoming content will be placed after any pre-existing content. This structure allows you to use an image block as the header of your newsletter rather than the email header option. Because of this, it is often ideal to create an ‘empty’ version of your designed template for use specifically with your API queries.
Where to find a post template ID
Post template IDs can be accessed from your beehiiv dashboard.
- Go to Start writing > My templates.
- Click the 3 dots icon for a template and select Edit template.
- In the URL for the template, you'll find the template ID listed after /posts/.
Adding dynamic content via the API
Dynamic content lets you show different content to different subscribers within a single post. In the beehiiv UI, this is configured using condition sets under Visibility settings in the Post Builder. The Send API exposes the same capability, allowing you to apply those same condition sets programmatically to individual blocks in your request.
How dynamic content via API works
Each block in a blocks request can include a visibility_settings object. This object controls both audience targeting (who sees the block based on subscription status, web vs. email, and more) and dynamic content conditions.
The fields covered in this section, condition_set_ids and condition_set_operator, are the dynamic content portion of visibility_settings. Additional fields such as show_on_web, show_on_email, show_to_free_subscribers, show_to_paid_subscribers, and referral-based conditions are also available within the same object. For the full list, refer to the API reference for visibility_settings.
Step 1: Create your condition sets in the Post Builder
Condition sets must be created in the beehiiv UI before they can be referenced in the API. You cannot define new condition sets through the API directly.
- Open any post in the Post Builder.
- Select a content block and open Visibility settings.
- Define the conditions for your condition set and save it.
- Make sure the condition set is active. Deactivated condition sets will be rejected with an error when referenced in an API request.
For a full walkthrough of condition sets and dynamic content, see Using dynamic content in your newsletter.
Step 2: Fetch your condition set IDs
Your API request references condition sets by their IDs. To retrieve them, call the List condition sets endpoint (GET /publications/{publicationId}/condition_sets). This returns all active condition sets for your publication and supports filtering by purpose (for example, dynamic_content) to narrow results. Note the IDs for the condition sets you want to use.
Step 3: Include visibility settings in your blocks request
Add a visibility_settings object to any block you want to show conditionally. Set condition_set_ids to an array of the condition set IDs you want to apply, and set condition_set_operator to "and" (subscriber must match all conditions) or "or" (subscriber must match at least one condition). If condition_set_operator is omitted, it defaults to "or".
Blocks without a visibility_settings object are shown to all subscribers as normal.
Working with custom HTML and CSS
As a fixed system, any custom HTML being used will need to utilize existing CSS classes from our email header or be added to the email header of your template. We recommend keeping HTML structures as simple as possible to minimize conflicts with our existing assets.
Adding custom CSS rules
Additional CSS classes required for your custom HTML can be placed in the Style panel of your template. Open the post template and access the Style panel on the right.
Go to: Advanced > Email Header > Code > Header custom css.
Using beehiiv’s HTML as a foundation for custom code
It’s best practice to recreate your layout in the beehiiv UI and then export the post HTML to use as the basis of your custom code. This keeps your HTML/CSS aligned with beehiiv’s fixed email structure and preserves mobile responsiveness.
To view the CSS classes available for custom HTML:
- Recreate a post and then save it.
- Go to your Posts list, and click the post to view it.
- From the post page, click the Edit post dropdown arrow.
- Select Download HTML.
The downloaded file provides a reliable foundation for writing custom HTML that stays compatible with beehiiv’s structure.
Sample testing workflows
For posts utilizing both blocks and custom HTML, use this process:
- Design a sample post using the beehiiv UI including all of the blocks you’ll be using in your posts. This captures all the design defaults that will be used in your posts.
- Export the raw HTML from the post and use this as your baseline for custom code (see steps above).
- Convert the post to a template, empty the contents (except for what you want the post to start with before your API-added content), and take note of the post_template_id.
- Use your chosen test environment to configure your API call’s headers and body (in JSON format) with the request objects you need.
A list of request objects can be found in our developer docs.
Sample request using blocks (including HTML snippet)
To include custom HTML, use the HTML Snippet block in the beehiiv Post Builder. For your code to be valid inside JSON, make sure all HTML is properly backslash-escaped.
Request body example:
{
"title": "Create Post blocks example",
"post_template_id": "post_template_572158ea-76d0-429a-9a31-39280e0c601b",
"blocks": [
{
"type": "heading",
"level": "1",
"text": "This is a heading block"
},
{
"type": "html",
"html": "<table class=\"mob-w-full\" width=\"100%\"><tr><td class=\"mob-stack\" width=\"50%\" align=\"center\" style=\"background:#2D2D2D; padding:20px 0; color:#FFFFFF;\"> Column One Content</td><td class=\"mob-stack\" width=\"50%\" align=\"center\" style=\"background:#2D2D2D; padding:20px 0; color:#FFFFFF;\">Column Two Content</td></tr></table>"
},
{
"type": "paragraph",
"plaintext": "This is a paragraph."
}
],
"status": "draft"
}Output:
Sample request using body_content
In most cases, a simple table structure will suffice to ensure that styling can be added as desired. If no styling is inlined on your HTML, elements will inherit styling from your template:
Table input example:
|
Custom HTML:
<table> <tbody> <tr> <td> <h1>Welcome to beehiiv!</h1> <p>This content was created by using the <i>body_content</i> parameter in the Create Post API.</p> </td> </tr> </tbody> </table>
|
Request body:
{ "title": "Create Post body_content example", "post_template_id": "572158ea-76d0-429a-9a31-39280e0c601b", "body_content": "<table>\n\t<tbody>\n\t\t<tr>\n\t\t\t<td style=\"padding-left: 20px; padding-right: 20px; background: #AEE2DB; \">\n\t\t\t\t<h1>Welcome to beehiiv!</h1>\n\t\t\t\t<p>This content was created by using the <i>body_content</i> parameter in the Create Post API.</p>\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>", "status": "draft" }
|
Output: