Integration·Beehiiv·intermediate
AI content for Beehiiv
AI content for Beehiiv: send Crontent research drafts into Beehiiv as newsletter or blog posts via the Beehiiv API.
How-to: Integrate Crontent with Beehiiv. Official docs: Beehiiv. Shared API contract: Publishing API and SDK.
Verify the Crontent webhook, fetch the post, and create a Beehiiv draft via the API for review before send or publish.
Field mapping
| Crontent field | Beehiiv field |
|---|---|
title | title |
seo_title | SEO title meta (if using blog posts) |
slug | URL slug on Beehiiv blog |
excerpt | subtitle or meta description |
body_mdx | Convert to HTML for content |
body_html | content (preferred) |
tags | Tags if supported on your plan |
hero_image_url | Header/thumbnail image |
canonical_url | Custom field or link block |
sources[] | Footer section in HTML body |
Webhook to Beehiiv draft
ts
import { Crontent } from "@crontent/sdk";
const crontent = new Crontent({ apiKey: process.env.CRONTENT_API_KEY! });
function appendSources(html: string, sources: { url: string; title: string | null }[]) {
if (!sources.length) return html;
const list = sources.map((s) => `<li><a href="${s.url}">${s.title ?? s.url}</a></li>`).join("");
return html + `<h2>Sources</h2><ul>${list}</ul>`;
}
async function createBeehiivDraft(post: Awaited<ReturnType<typeof crontent.posts.get>>) {
const content = appendSources(post.body_html ?? `<p>${post.excerpt}</p>`, post.sources);
const res = await fetch(
`https://api.beehiiv.com/v2/publications/${process.env.BEEHIIV_PUBLICATION_ID}/posts`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BEEHIIV_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: post.title,
subtitle: post.excerpt,
content,
status: "draft",
}),
}
);
if (!res.ok) throw new Error(await res.text());
return res.json();
}
export async function handleWebhook(req: Request) {
const rawBody = await req.text();
const valid = await crontent.webhooks.verify({
rawBody,
signature: req.headers.get("x-crontent-signature"),
timestamp: req.headers.get("x-crontent-timestamp"),
secret: process.env.CRONTENT_WEBHOOK_SECRET!,
});
if (!valid) return new Response("unauthorized", { status: 401 });
const { post_id } = JSON.parse(rawBody);
const post = await crontent.posts.get(post_id);
await createBeehiivDraft(post);
return new Response("ok");
}Review drafts in the Beehiiv dashboard. Choose "Send newsletter" or "Publish to web" depending on your workflow.
Backfill
Use posts.list to import historical content as drafts. Beehiiv rate limits apply; batch with delays.
Environment variables
text
CRONTENT_API_KEY=...
CRONTENT_WEBHOOK_SECRET=...
BEEHIIV_API_KEY=...
BEEHIIV_PUBLICATION_ID=...