crontent
Integration·Prismic·advanced

Automated content for Prismic

Automated content for Prismic: push Crontent posts into Prismic drafts with the Migration API or a custom write path.

How-to: Integrate Crontent with Prismic. Official docs: Prismic. Shared API contract: Publishing API and SDK.

Prismic writes are constrained, so plan a Migration API or custom write path. Verify the Crontent webhook, fetch the post, then create a draft document editors can approve.

What you need

  • CRONTENT_API_KEY and CRONTENT_WEBHOOK_SECRET
  • A Prismic repository with a custom type (e.g. blog_post)
  • A Migration API access token (Prismic dashboard) or a middleware service that holds write credentials
  • Webhook receiver with @crontent/sdk

Register Crontent webhooks:

ts
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 Prismic

Crontent fieldPrismic fieldNotes
titletitleRich text or Key Text
seo_titlemeta_titleSEO metadata; fall back to title
sluguidDocument UID
excerptsummaryKey Text
body_mdx / body_htmlbodyRich text (convert HTML)
tagstagsGroup or Key Text list
hero_image_urlfeatured_imageLink to Media or external
canonical_urlcanonical_urlKey Text
sources[]sourcesRepeatable group
ready_atcrontent_ready_atTimestamp field

Crontent researches and drafts; you define angle in the brief. Store documents unpublished until an editor releases them in Prismic.

Receive and verify webhooks

Headers: X-Crontent-Signature, X-Crontent-Timestamp, X-Crontent-Delivery. Retries at 1m, 5m, 30m, 2h, 12h. Deduplicate on delivery ID.

ts
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 createPrismicDraft(post);
  await markSeen(deliveryId);
  return new Response("OK");
}

Create a draft in Prismic

Use the Migration API to create unpublished documents. Prismic does not expose a general-purpose public write API for arbitrary content creation.

ts
async function createPrismicDraft(post: Post) {
  const res = await fetch(
    `https://migration.prismic.io/documents`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.PRISMIC_MIGRATION_TOKEN}`,
        "Content-Type": "application/json",
        "x-api-key": process.env.PRISMIC_REPOSITORY!,
      },
      body: JSON.stringify({
        title: post.title,
        type: "blog_post",
        uid: post.slug,
        lang: "en-us",
        data: {
          title: [{ type: "heading1", text: post.title }],
          meta_title: post.seo_title ?? post.title,
          summary: post.excerpt,
          body: convertHtmlToPrismicRichText(post.body_html),
          sources: post.sources.map((s) => ({
            url: { link_type: "Web", url: s.url },
            label: s.title,
          })),
        },
      }),
    }
  );
  if (!res.ok) throw new Error(await res.text());
}

Alternative: store Crontent posts in your database and expose them to Prismic via Integration Fields for read-only preview, then migrate approved posts with the Migration API.

Backfill and polling

Use crontent.posts.list({ projectId, since, cursor }) to replay missed events. Track synced post.id values to avoid duplicate UIDs.

Official documentation