| name | beehiiv |
| description | Manage newsletters, subscribers, posts, automations, segments, polls, and analytics on Beehiiv. Use when the user asks about newsletters, email campaigns, subscriber lists, email stats, open rates, click rates, posts, drafts, scheduling emails, subscriber growth, segments, automations, referral programs, polls, custom fields, tiers, or anything related to Beehiiv. Also trigger when the user mentions sending newsletters, checking email performance, managing subscribers, creating email content, or importing contacts for newsletters. |
Beehiiv Newsletter API
Manage newsletters, subscribers, posts, analytics, and more via the Beehiiv API v2.
Authentication
All requests use Bearer token auth. The BEEHIIV_API_KEY env var must be set.
curl -s "https://api.beehiiv.com/v2/<endpoint>" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
API Conventions
- Base URL:
https://api.beehiiv.com/v2
- Reads: GET requests with query params
- Writes: POST/PUT/DELETE requests with JSON body
- Dates: Unix timestamps (seconds since epoch) in responses
- Pagination: Cursor-based — use
limit (1-100, default 10) and cursor; response includes has_more and next_cursor in a pagination object. Always paginate through all pages when counting totals.
- Rate limits: 180 requests per minute per organization. Check
RateLimit-Remaining header.
- Expand: Many endpoints support
expand[] params to include extra data (e.g., stats, custom_fields)
Publications
The {pubId} placeholder is required in most endpoints. Use /v2/publications to list yours.
curl -s "https://api.beehiiv.com/v2/publications" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}?expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Stats include: active_subscriptions, active_premium_subscriptions, active_free_subscriptions, average_open_rate, average_click_rate, total_sent, total_unique_opened, total_clicked.
Posts
List posts
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/posts?expand[]=stats&limit=20" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Query params: status (draft/confirmed/archived), audience (free/premium/both), platform (web/email/both), content_tags[], order_by (created/publish_date/displayed_date), direction (asc/desc), expand[] (stats/free_web_content/free_email_content/premium_web_content/premium_email_content), limit, cursor.
Get a post
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/posts/{postId}?expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Create a post (draft or scheduled) — Enterprise plan only
This endpoint requires an Enterprise plan. Non-Enterprise accounts get a 403 SEND_API_NOT_ENTERPRISE_PLAN error. If you hit this, tell the user drafts must be created via the Beehiiv web dashboard instead.
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/posts" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Weekly Update",
"subtitle": "What happened this week",
"body_content": "<p>Your HTML content here</p>",
"status": "draft",
"content_tags": ["weekly"]
}'
Fields: title (required), body_content or blocks (one required — body_content is raw HTML, blocks is structured), subtitle, status (draft/confirmed), scheduled_at (ISO 8601 — only with status=confirmed), thumbnail_image_url, recipients, email_settings, web_settings, seo_settings, content_tags[], post_template_id.
Delete/archive a post
curl -s -X DELETE "https://api.beehiiv.com/v2/publications/{pubId}/posts/{postId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Aggregate stats across posts
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/posts/aggregate_stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Returns: recipients, delivered, opens, unique_opens, open_rate, clicks, unique_clicks, click_rate, unsubscribes, spam_reports, plus web views/clicks.
Subscribers (Subscriptions)
List subscribers
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions?expand[]=stats&expand[]=custom_fields&limit=50" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Query params: status (active/inactive/pending/validating/invalid/all), tier (free/premium), email (filter by email), order_by (created/email), direction (asc/desc), expand[] (stats/custom_fields/referrals/subscription_premium_tiers/tags), limit, cursor.
Get subscriber by email
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/by_email/user%40example.com" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
The email must be URL-encoded (@ becomes %40).
Get subscriber by ID
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/{subId}?expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Create subscriber
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "new@example.com",
"reactivate_existing": true,
"send_welcome_email": true,
"utm_source": "api",
"custom_fields": [
{"name": "Company", "value": "Acme Corp"}
]
}'
Fields: email (required), reactivate_existing, send_welcome_email, utm_source/medium/campaign, referral_code, custom_fields[] ({name, value}), double_opt_override (on/off/not_set), tier (free/premium), automation_ids[].
Update subscriber
curl -s -X PUT "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/{subId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"custom_fields": [
{"name": "Company", "value": "New Corp"}
]
}'
Can also update by email: PUT .../subscriptions/by_email/{email}
Fields: tier, email, unsubscribe (true to unsubscribe), custom_fields[] ({name, value, delete}), premium_tier_ids[].
Delete subscriber (permanent, irreversible)
curl -s -X DELETE "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/{subId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Add tag to subscriber
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/{subId}/tags" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tag": "vip"}'
Bulk operations
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/bulk" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subscriptions": [
{"email": "a@example.com"},
{"email": "b@example.com"}
]
}'
curl -s -X PUT "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/bulk" ...
curl -s -X PUT "https://api.beehiiv.com/v2/publications/{pubId}/subscriptions/bulk/status" ...
Segments
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/segments?expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/segments/{segId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/segments/{segId}/subscriptions?limit=50" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X PUT "https://api.beehiiv.com/v2/publications/{pubId}/segments/{segId}/recalculate" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X DELETE "https://api.beehiiv.com/v2/publications/{pubId}/segments/{segId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Query params for list: type (dynamic/static/manual/all), status (pending/processing/completed/failed/all), order_by (created/last_calculated), expand[] (stats).
Automations
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/automations" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/automations/{autoId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/automations/{autoId}/journeys" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/automation_journeys" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Automation statuses: running, finishing, inactive, live, draft. Journey statuses: in_progress, completed, exited_early, manually_removed.
Custom Fields
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/custom_fields" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/custom_fields" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind": "string", "display": "Company Name"}'
Field types: string, integer, boolean, date, datetime, list, double.
Polls
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/polls?expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/polls/{pollId}?expand[]=poll_responses&expand[]=stats" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/polls/{pollId}/responses" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Poll types: voting, trivia.
Tiers (Premium)
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/tiers?expand[]=stats&expand[]=prices" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/tiers" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Pro", "description": "Premium access"}'
Referral Program
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/referral_program" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Returns milestones with reward info (physical, promo_code, digital, premium_gift).
Webhooks
curl -s "https://api.beehiiv.com/v2/publications/{pubId}/webhooks" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
curl -s -X POST "https://api.beehiiv.com/v2/publications/{pubId}/webhooks" \
-H "Authorization: Bearer $BEEHIIV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook",
"event_types": ["subscription.created", "post.sent"]
}'
curl -s -X DELETE "https://api.beehiiv.com/v2/publications/{pubId}/webhooks/{whId}" \
-H "Authorization: Bearer $BEEHIIV_API_KEY"
Event types: post.sent, post.updated, subscription.created, subscription.confirmed, subscription.deleted, subscription.upgraded, subscription.downgraded, subscription.paused, subscription.resumed, subscription.tier.paused, subscription.tier.resumed, subscription.tier.created, subscription.tier.deleted, survey.response_submitted.
Common Workflows
Check newsletter performance
- Get publication stats:
GET /v2/publications/{pubId}?expand[]=stats
- Get aggregate post stats:
GET /v2/publications/{pubId}/posts/aggregate_stats
- List recent posts with stats:
GET /v2/publications/{pubId}/posts?expand[]=stats&order_by=publish_date&direction=desc&limit=10
See how a specific post performed
- List posts to find the one:
GET .../posts?order_by=publish_date&direction=desc&limit=5&expand[]=stats
- Or get by ID:
GET .../posts/{postId}?expand[]=stats
- Stats include: recipients, opens, unique_opens, open_rate, clicks, click_rate, unsubscribes
Check subscriber growth
- Get publication stats for totals:
GET /v2/publications/{pubId}?expand[]=stats
- List recent subscribers:
GET .../subscriptions?order_by=created&direction=desc&limit=20&expand[]=stats
Find a subscriber
- By email:
GET .../subscriptions/by_email/{url-encoded-email}?expand[]=stats&expand[]=custom_fields
- The email must be URL-encoded (@ → %40, + → %2B, etc.)
Create and schedule a post
- Create as draft first:
POST .../posts with status: "draft" and body_content (HTML)
- To schedule: set
status: "confirmed" and scheduled_at: "2026-03-15T14:00:00Z"
- Without
scheduled_at, status=confirmed sends immediately
Notes
- Publication IDs look like
pub_xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- Post content uses HTML in
body_content — not markdown
- Subscriber DELETE is permanent and irreversible — prefer
unsubscribe: true via PUT
expand[] is critical — without it, stats fields return null/N/A. Always include expand[]=stats when you need open rates, click rates, or engagement data. For post content, add expand[]=free_web_content and/or expand[]=free_email_content. You can combine multiple: expand[]=stats&expand[]=free_web_content
- For accurate subscriber counts, use publication stats (
GET /v2/publications/{pubId}?expand[]=stats → active_subscriptions), not segment counts — segments may be stale if not recently recalculated
- Always paginate with cursor-based pagination (not offset/page — that's deprecated)