How do I access content via API and MCP?
The Better i18n Content API lets you manage structured multilingual content — think blog posts, help articles, product descriptions — with a read API for your app and MCP tools for AI agents.
What is the Content API? #
Unlike the Translation API (which manages i18n keys in your code), the Content API manages free-form content entries in a CMS-like structure. Each entry has:
- A title
- A rich markdown body
- Custom fields you define
- Multiple language translations
Reading content #
Base URL: https://content.better-i18n.com/v1/content/{org}/{project}
Authentication is the x-api-key header — not Authorization: Bearer:
curl "https://content.better-i18n.com/v1/content/your-org/your-project/models/help-article/entries?status=published" \
-H "x-api-key: YOUR_API_KEY"Three routes, all GET:
| Route | Returns |
|---|---|
/models | Every content model in the project |
/models/{model}/entries | A page of entries |
/models/{model}/entries/{entrySlug} | One entry |
Useful query parameters on the entries route:
| Parameter | Notes |
|---|---|
language | Defaults to the project's source language |
status | No default filter — pass status=published or drafts come back too |
page, limit | limit defaults to 50, caps at 100 |
sort, order | publishedAt, createdAt, updatedAt, title · asc / desc |
search | Matches title and searchable text fields |
fields, expand | Trim the payload, or resolve relation fields inline |
bodyFormat | markdown (default), html, or plate |
Responses are cached at the edge (s-maxage=60, stale-while-revalidate=120) and the cache is purged when you publish, so you get fresh content without a redeploy.
Writing content #
The Content API is read-only. Creating, editing, publishing and deleting happen in the dashboard or through MCP — there is no POST on content.better-i18n.com. That split is deliberate: the read surface is the one your app calls with a key on every request, so it stays a surface that cannot mutate anything.
Content models #
Before creating entries, you define a content model — a schema for your content type. For example:
{
"slug": "help-article",
"displayName": "Help Article",
"fields": [
{ "name": "excerpt", "type": "textarea", "localized": true },
{ "name": "category", "type": "enum", "options": ["setup", "billing", "api"] },
{ "name": "order", "type": "number" }
]
}Using the MCP server #
The Better i18n MCP server exposes content management as tools for AI agents:
# In Claude Code or Cursor:
"List all help articles in my better-i18n/help project"
"Translate the getting-started article to Spanish"
"Create a new help article about API authentication"Models: listContentModels, getContentModel, createContentModel, updateContentModel
Entries: listContentEntries, getContentEntry, createContentEntry, updateContentEntry, duplicateContentEntry, deleteContentEntry
Bulk: bulkCreateEntries, bulkUpdateEntries (max 200 per call), bulkPublishEntries (max 500)
Publishing: publishContentEntry
Two habits worth keeping: pass every language in the initial createContentEntry call rather than looping one update per language, and use missingLanguage=fr — not language=fr — when you are looking for entries that still need translating.
Content vs. Translation API #
| Use case | API to use |
|---|---|
t('auth.login') keys in your code | Translation API |
| Blog posts, help articles, product descriptions | Content API |
| Structured CMS content with custom fields | Content API |
| Simple key-value i18n strings | Translation API |
Better I18N