Contentful Integration

Contentful Integration

Contentful Integration

Connect your Contentful space to Wrodium for enterprise-grade content optimization.

Created date:

Dec 5, 2025

Updated date:

Dec 11, 2025

Prerequisites

  • Contentful account with a Space

  • Content Management API (CMA) access

  • A Content Type for your articles/posts

  • Organization Admin or Space Admin permissions

Setup Steps

Step 1: Generate a Management Token

  1. Go to Settings → API Keys in your Contentful space

  2. Click the Content management tokens tab

  3. Click Generate personal token

  4. Give it a name (e.g., "Wrodium Integration")

  5. Copy the token immediately

Important: Management tokens have full read/write access. Store securely.

Step 2: Find Your Space and Environment IDs

Space ID:

  • In Contentful, go to Settings → General Settings

  • Copy the Space ID

Environment ID:

  • Usually master (default)

  • For other environments, check Settings → Environments

Step 3: Identify Your Content Type

  1. Go to Content Model in Contentful

  2. Click on your article/post content type

  3. Note the Content Type ID (shown in the URL or sidebar)

  4. Note the Field IDs for:

    • Title (e.g., title)

    • Body/content (e.g., body)

    • Excerpt (e.g., excerpt)

    • Slug (e.g., slug)

Step 4: Configure Wrodium

  1. Go to Settings → CMS Connection in Wrodium

  2. Select Contentful as your provider

  3. Enter your configuration:

Field

Value

Management Token

Your CMA token

Space ID

Your space ID

Environment ID

master (or your environment)

Content Type ID

Your content type (e.g., blogPost)

Locale

en-US (or your locale)

Title Field

Field ID for title

Content Field

Field ID for body

Excerpt Field

Field ID for excerpt

Slug Field

Field ID for URL slug

Site Base URL

https://yourblog.com/blog

  1. Click Test Connection then Save

Configuration Schema

{
  "provider": "contentful",
  "provider_config": {
    "management_token": "CFPAT-xxxxxxxxxxxxxxxxxxxxx",
    "space_id": "your-space-id",
    "environment_id": "master",
    "content_type_id": "blogPost",
    "locale": "en-US",
    "title_field": "title",
    "content_field": "body",
    "excerpt_field": "excerpt",
    "slug_field": "slug",
    "site_base_url": "https://yourblog.com/blog"
  }
}

API Behavior

Listing Articles

Wrodium queries entries via the Content Management API:


Updating Articles

Updates use optimistic locking with the X-Contentful-Version header:

  1. Fetch current entry to get the version number

  2. PUT updated entry with the version header

PUT /spaces/{space_id}/environments/{env}/entries/{entry_id}
Headers:
  X-Contentful-Version: {current_version}
Body:
  {
    "fields": {
      "title": { "en-US": "Updated Title" },
      "body": { "en-US": "<p>Updated content...</p>

Publishing After Update

By default, Wrodium updates draft content. To auto-publish, enable the "Publish after update" option or call the publish endpoint separately:


Localization

Contentful requires locale-aware field access:

{
  "fields": {
    "title": {
      "en-US": "English Title",
      "de-DE": "German Title"
    }
  }
}

Wrodium uses the locale from your configuration for all reads and writes.

Rich Text Fields

If your content field uses Contentful's Rich Text type, the update payload changes:

{
  "fields": {
    "body": {
      "en-US": {
        "nodeType": "document",
        "data": {},
        "content": [
          {
            "nodeType": "paragraph",
            "data": {},
            "content": [
              {
                "nodeType": "text",
                "value": "Your content here",
                "marks": [],
                "data": {}
              }
            ]
          }
        ]
      }
    }
  }
}

For Rich Text fields, Wrodium automatically converts HTML to Contentful's Rich Text format.

Troubleshooting

"401 Unauthorized" Error

  • Management tokens don't expire, but they can be revoked

  • Verify you're using a CMA token (starts with CFPAT-), not a CDA token

"409 Conflict" Error (Version Mismatch)

  • Another user or process updated the entry

  • Wrodium will automatically retry with the new version

"422 Validation Failed" Error

  • Check that all required fields are included

  • Verify field values match their expected types

  • Ensure the locale is valid for your space

Content Not Appearing on Site

  • Entry may be saved but not published

  • Enable "Publish after update" in Wrodium settings

  • Check Contentful's publish queue

Code Example

import httpx

class ContentfulClient:
    BASE = "https://api.contentful.com"
    
    def __init__(self, config: dict):
        self.token = config["management_token"]
        self.space_id = config["space_id"]
        self.env_id = config.get("environment_id", "master")
        self.content_type = config["content_type_id"]
        self.locale = config.get("locale", "en-US")
        self.title_field = config.get("title_field", "title")
        self.content_field = config.get("content_field", "body")
    
    def _headers(self):
        return {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/vnd.contentful.management.v1+json",
        }
    
    def _entries_path(self):
        return f"/spaces/{self.space_id}/environments/{self.env_id}/entries"
    
    async def list_articles(self, limit: int = 20):
        params = {
            "content_type": self.content_type,
            "limit": limit,
            "order": "-sys.publishedAt",
        }
        async with httpx.AsyncClient(base_url=self.BASE, timeout=15) as client:
            resp = await client.get(
                self._entries_path(),
                headers=self._headers(),
                params=params
            )
            resp.raise_for_status()
        return resp.json().get("items", [])
    
    async def update_article(self, article_id: str, updates: dict):
        entry_url = f"{self._entries_path()}/{article_id}"
        
        async with httpx.AsyncClient(base_url=self.BASE, timeout=15) as client:
            # Get current entry for version and existing fields
            current = await client.get(entry_url, headers=self._headers())
            current.raise_for_status()
            entry = current.json()
            
            fields = entry.get("fields", {})
            version = entry["sys"]["version"]
            
            # Update fields with locale
            if "title" in updates:
                fields.setdefault(self.title_field, {})
                fields[self.title_field][self.locale] = updates["title"]
            if "content" in updates:
                fields.setdefault(self.content_field, {})
                fields[self.content_field][self.locale] = updates["content"]
            
            # PUT with version header
            headers = dict(self._headers())
            headers["X-Contentful-Version"] = str(version)
            
            resp = await client.put(
                entry_url,
                headers=headers,
                json={"fields": fields}
            )
            resp.raise_for_status()
        return resp.json()

Webhooks (Optional)

Set up Contentful webhooks to notify Wrodium when content changes:

  1. Go to Settings → Webhooks in Contentful

  2. Add a webhook pointing to:

  3. Select events: Entry.publish, Entry.unpublish

Next Steps

Found this article insightful? Spread the words on…

Found this article insightful?
Spread the words on…

X.com

Share on X

X.com

Share on X

X.com

Share on X

X.com

Share on LinkedIn

X.com

Share on LinkedIn

X.com

Share on LinkedIn

Found this documentation insightful? Share it on…

X.com

LinkedIn

Contents

Checkout other documentations

Checkout other documentations

Checkout other documentations

Let us help you win on

ChatGPT

Let us help you win on

ChatGPT

Let us help you win on

ChatGPT