Automated blog posts for Hygraph
Automated blog posts for Hygraph: connect Crontent webhooks and create draft Hygraph entries with the Content API.
How-to: Integrate Crontent with Hygraph. Official docs: Hygraph. Shared API contract: Publishing API and SDK.
Verify the Crontent webhook, then create a Hygraph draft through the Content API with mapped titles, body, and sources.
What you need
CRONTENT_API_KEYandCRONTENT_WEBHOOK_SECRET- Hygraph project with a
Postmodel and Content API permanent auth token - Webhook endpoint with
@crontent/sdkand a GraphQL client (orfetch)
Register the webhook:
await crontent.webhooks.register({
projectId: process.env.CRONTENT_PROJECT_ID!,
url: "https://your-app.com/api/crontent/webhook",
events: ["post.ready"],
});Map Crontent fields to Hygraph
| Crontent field | Hygraph field | Notes |
|---|---|---|
title | title | String, display H1 |
seo_title | seoTitle | Meta title; fall back to title |
slug | slug | Unique string |
excerpt | excerpt | String |
body_mdx / body_html | content | Rich text (convert HTML to AST) |
tags | tags | String list or relation |
hero_image_url | heroImage | Asset or URL |
canonical_url | canonicalUrl | String |
sources[] | sources | JSON or component model |
ready_at | crontentReadyAt | DateTime |
Crontent researches and drafts on your schedule; you set angle in the brief. Hygraph draft stages keep content out of the published API until release.
Receive and verify webhooks
Deduplicate on X-Crontent-Delivery. Failed deliveries retry at 1m, 5m, 30m, 2h, 12h.
import { Crontent } from "@crontent/sdk";
const crontent = new Crontent({ apiKey: process.env.CRONTENT_API_KEY! });
export async function POST(req: Request) {
const rawBody = await req.text();
const deliveryId = req.headers.get("x-crontent-delivery")!;
if (await seen(deliveryId)) return new Response("OK");
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 createHygraphDraft(post);
await markSeen(deliveryId);
return new Response("OK");
}Create a draft in Hygraph
Use a Content API mutation. Enable draft stages in your model, then create without publishing.
async function createHygraphDraft(post: Post) {
const mutation = `
mutation CreatePost($data: PostCreateInput!) {
createPost(data: $data, stage: DRAFT) {
id
slug
}
}
`;
const res = await fetch(process.env.HYGRAPH_CONTENT_API!, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HYGRAPH_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: mutation,
variables: {
data: {
title: post.title,
seoTitle: post.seo_title ?? post.title,
slug: post.slug,
excerpt: post.excerpt,
content: { html: post.body_html },
tags: post.tags,
sources: post.sources,
crontentPostId: post.id,
},
},
}),
});
if (!res.ok) throw new Error(await res.text());
}Adjust stage: DRAFT and field names to match your schema and stage configuration.
Backfill and polling
Poll crontent.posts.list({ projectId, since, limit, cursor }) and skip entries with matching crontentPostId. Useful for recovery after downtime.