API

PrestaBlog provides a REST API that allows external tools - scripts, third-party software, or AI agents - to create and manage blog articles and categories without using the back office. This feature, available starting from PrestaShop 8, is designed both for non-developers via an AI agent, and for developers who want a direct integration.

API configuration

First, the API must be enabled and configured in the back office.

Open the configuration:
Modules > PrestaBlog > Configuration > Tools > API

Available settings:

  • Enable API: main toggle. The API will not respond to any request while disabled.
  • API key: click “Generate a new key”. The key is displayed only once - copy it immediately, it will not be accessible again. Only its cryptographic fingerprint (SHA-256) is stored. If you lose the key, generate a new one.
  • Automatically enable new articles: decides whether articles created via the API are published immediately or saved as drafts when the request does not explicitly provide this parameter.
  • Rate limit: maximum number of requests per minute per IP address (default: 60).
  • Image security: blocks image downloads from private/internal IP ranges. Recommended for installations exposed to the Internet.
  • Behind a proxy: enable if your shop is behind Cloudflare, a reverse proxy, or a CDN, to handle client IP correctly.
  • Log level: None disables logs. Security logs failed auth attempts and blocks. Debug logs all requests (use temporarily for diagnosis).
  • Allowed CORS origins: only if a web app hosted on another domain must call the API from a browser. Leave empty in most cases.

API permissions

The API permissions section lets you restrict precisely what the API key is allowed to do. Each operation can be enabled or disabled independently, both for articles and categories.

  • Allow creating articles / categories: allows POST requests to create new content.
  • Allow updating articles / categories: allows PUT requests to update existing content.
  • Allow deleting articles / categories: allows DELETE requests. Disable this if you want to prevent accidental deletions from an AI agent or a third-party script.
Best practice Only grant the permissions you strictly need. If you use the API only to publish articles, disable update and delete to reduce risk in case the key is compromised.
Security

The API requires HTTPS. Over HTTP, all requests are rejected (except from localhost for local development tests). Never share your API key.

Use via an AI agent (recommended)

You are not a developer, or you don't want to write code? The easiest method is to use an AI agent like Claude through the MCP protocol (Model Context Protocol). The agent knows exactly which calls to make, handles authentication, and understands your instructions in natural language.

Note: Claude and Windsurf are examples of MCP integrations. There are many other compatible software tools and environments, but it is not possible to review all of them here.

1. Enable the API and generate your key

In the PrestaBlog back office: Tools > API. Enable the API, click “Generate a new key”, and copy the displayed key - it will not be accessible again.

2. Build your MCP connection URL

The connection URL follows this format:

https://prestablog-mcp.prestablog.workers.dev/mcp?key=YOUR_KEY&shop=https://your-shop.com

Replace YOUR_KEY with the key you generated and https://your-shop.com with your shop URL.

Do not confuse this with the “API URL”, which is a different URL used for direct calls.

Important

The URL contains your API key. Treat it like a password: do not share it and do not publish it.

3. Set up with Claude

In Claude, click Customize at the top left, then Connectors,
at the top of the column that appears click the + button, then Add a custom connector.

Fill in:

  • Name: anything you want (e.g. PrestaBlog API)
  • URL: the MCP connection URL you built in step 2

Confirm. Claude can now access your blog and can create, edit, and delete your articles and categories directly.

Examples of what you can ask Claude:

  • “Create an article about summer shoes in the Fashion category”
  • “List the 10 latest published articles”
  • “Change the title of article 42”
  • “Create a new category called News with this description”
  • “Delete category 5”

Built-in documentation

Full documentation is built into the MCP connector. Claude reads it automatically, there is nothing else to configure.

4. Set up with Windsurf

In Windsurf, open the Cascade panel, click ... in the top right corner of the panel, then click the MCPs icon (the last icon at the bottom right of the menu). An editor window opens. Add the following configuration after generating the URL correctly (see step 2):

{
  "mcpServers": {
    "prestablog": {
      "serverUrl": "https://prestablog-mcp.prestablog.workers.dev/mcp?key=YOUR_KEY&shop=https://your-shop.com"
    }
  }
}

Save. Cascade displays 1 MCP at the bottom of the panel, confirming the connection is active.

Examples of what you can ask Cascade:

  • “Create an article about summer shoes in the Fashion category”
  • “List the 10 latest published articles”
  • “Change the title of article 42”
  • “Create a new category called News with this description”
  • “Delete category 5”

Built-in documentation

Full documentation is built into the MCP connector. Cascade reads it automatically, there is nothing else to configure.

Authentication (REST)

Each request must include the API key in an HTTP header. Two formats are supported:

Authorization: Bearer YOUR_API_KEY

or

X-Api-Key: YOUR_API_KEY

Best practice

The key should never be sent as a URL parameter, to avoid it appearing in server logs.

Automatic blocking: after 5 failed authentication attempts from the same IP, it is blocked for 1 hour. This delay is configurable in the API settings.

Articles

List articles

GET /prestablog-api/articles

Returns the paginated list of articles. Available parameters: lang (language ID), page, per_page (max 100), active (1 = published only), category (category ID), search (search in title), sort (date, title, id), order (asc, desc).

curl -X GET "https://your-shop.com/prestablog-api/articles?lang=1&page=1&per_page=10" \
  -H "Authorization: Bearer YOUR_KEY"

Article details

GET /prestablog-api/articles/{id}

Returns all data for an article: multilingual fields, categories, associated products, related articles, table of contents.

curl -X GET "https://your-shop.com/prestablog-api/articles/18" \
  -H "Authorization: Bearer YOUR_KEY"

Create an article

POST /prestablog-api/articles

Minimal example:

curl -X POST "https://your-shop.com/prestablog-api/articles" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "languages": {
      "1": {
        "title": "My article",
        "content": "<h2>Introduction</h2><p>Article content.</p>"
      }
    },
    "categories": [1],
    "active": true
  }'

Full example with image, multilingual content, and metadata:

{
  "languages": {
    "1": {
      "title": "My article",
      "introduction": "Short text displayed in listings",
      "content": "<h2>Section</h2><p>Full HTML content.</p>",
      "meta_title": "My article - SEO Title",
      "meta_description": "Search engine description",
      "meta_keywords": "word1, word2",
      "link_rewrite": "my-article"
    },
    "2": {
      "title": "My article",
      "introduction": "Short text displayed in listings",
      "content": "<h2>Section</h2><p>Full HTML content.</p>"
    }
  },
  "categories": [2, 5],
  "active": true,
  "date": "2026-06-15 09:00:00",
  "enable_toc": true,
  "author_id": 1,
  "image": {
    "url": "https://example.com/image.jpg"
  }
}

Available fields:

FieldTypeDescription
languagesobjectContent per language, indexed by PrestaShop language ID. Required on creation
languages.{id}.titletextArticle title. Required for each language
languages.{id}.introductionHTMLShort text displayed in listings and at the top of the article
languages.{id}.contentHTMLArticle body
languages.{id}.meta_titletextSEO title tag (max 500 chars)
languages.{id}.meta_descriptiontextMeta description (max 500 chars)
languages.{id}.meta_keywordstextSEO keywords
languages.{id}.link_rewritetextURL slug. Automatically generated from the title if missing
categoriesarray of IDsPrestaBlog categories to associate
productsarray of IDsAssociated PrestaShop products
related_articlesarray of IDsRelated articles
activebooleanImmediate publish. If absent, uses the “Automatically enable” setting
datedatetimePublication date in YYYY-MM-DD HH:MM:SS. A future date schedules publication
enable_tocbooleanEnables table of contents generated from h2/h3 tags in content
author_idintegerPrestaBlog author ID
image.urlURLMain image to download from a remote URL
id_shopintegerShop ID (multishop only). Default: current shop

Update an article

PUT /prestablog-api/articles/{id}

Partial update: only fields present in the request are updated. Fields not provided keep their current value. For languages, only those included in the payload are updated.

curl -X PUT "https://your-shop.com/prestablog-api/articles/18" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "active": false,
    "languages": {
      "1": {
        "title": "New title"
      }
    }
  }'

Delete an article

DELETE /prestablog-api/articles/{id}

Deletes the article and all related data: images (all variants), categories, linked products, related articles.

curl -X DELETE "https://your-shop.com/prestablog-api/articles/18" \
  -H "Authorization: Bearer YOUR_KEY"

Article image

POST /prestablog-api/articles/{id}/image

Three methods are available depending on your context:

Remote URL (image hosted online):

curl -X POST "https://your-shop.com/prestablog-api/articles/18/image" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/image.jpg"}'

Local file (multipart upload):

curl -X POST "https://your-shop.com/prestablog-api/articles/18/image" \
  -H "Authorization: Bearer YOUR_KEY" \
  -F "file=@/path/to/image.jpg"

Base64 (fallback):

Note: base64 is very large and can become difficult to handle for complex images. When possible, prefer uploading via remote URL.

curl -X POST "https://your-shop.com/prestablog-api/articles/18/image" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"base64": "/9j/4AAQSkZJRg...", "filename": "photo.jpg"}'

Via MCP (Claude)

Only URL and base64 methods are available via MCP. To send a local file via Claude, encode it to base64 first.

Categories

The API allows you to create, view, update, and delete categories, just like for articles.

List categories

GET /prestablog-api/categories

Returns categories as a tree by default. Use flat=1 for a flat list, active=1 for active only, lang for the language.

curl -X GET "https://your-shop.com/prestablog-api/categories?lang=1" \
  -H "Authorization: Bearer YOUR_KEY"

Category details

GET /prestablog-api/categories/{id}

Returns all category data: multilingual fields, article count, associated customer groups.

Create a category

POST /prestablog-api/categories

Minimal example:

curl -X POST "https://your-shop.com/prestablog-api/categories" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "languages": {
      "1": {
        "title": "News"
      }
    },
    "active": true
  }'

Full example:

{
  "languages": {
    "1": {
      "title": "News",
      "description": "<p>All news from our shop.</p>",
      "meta_title": "News - SEO Title",
      "meta_description": "SEO description of the category",
      "meta_keywords": "news",
      "link_rewrite": "news"
    },
    "2": {
      "title": "News",
      "description": "<p>All the latest news from our shop.</p>",
      "link_rewrite": "news"
    }
  },
  "parent": 0,
  "position": 1,
  "active": true,
  "image": {
    "url": "https://example.com/category.jpg"
  }
}

Available fields:

FieldTypeDescription
languagesobjectContent per language. Required on creation
languages.{id}.titletextCategory title. Required for each language
languages.{id}.descriptionHTMLCategory description
languages.{id}.meta_titletextSEO title tag (max 500 chars)
languages.{id}.meta_descriptiontextMeta description (max 500 chars)
languages.{id}.meta_keywordstextSEO keywords
languages.{id}.link_rewritetextURL slug. Automatically generated from the title if missing
parentintegerParent category ID. 0 = root
positionintegerDisplay order
activebooleanCategory visible on the front
image.urlURLCategory image to download from a remote URL

Update a category

PUT /prestablog-api/categories/{id}

Partial update: only fields present in the request are updated.

curl -X PUT "https://your-shop.com/prestablog-api/categories/1" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "languages": {
      "1": {
        "title": "New category name",
        "description": "<p>New description.</p>"
      }
    }
  }'

Delete a category

DELETE /prestablog-api/categories/{id}

Deletes the category and all related data: image, links with articles, customer groups.

Warning

Articles associated with this category are not deleted, but they lose this category link.

curl -X DELETE "https://your-shop.com/prestablog-api/categories/1" \
  -H "Authorization: Bearer YOUR_KEY"

Category image

POST /prestablog-api/categories/{id}/image

Same three methods as for articles: remote URL, local file (multipart), or base64.

Note: base64 is very large and can become difficult to handle for complex images. When possible, prefer uploading via remote URL.

curl -X POST "https://your-shop.com/prestablog-api/categories/1/image" \
  -H "Authorization: Bearer YOUR_KEY" \
  -F "file=@/path/to/category.jpg"

Authors

Authors are read-only via the API. They must be created in the PrestaBlog back office.

  • GET /prestablog-api/authors - list all authors
  • GET /prestablog-api/authors/{id} - author details with multilingual bios
curl -X GET "https://your-shop.com/prestablog-api/authors?lang=1" \
  -H "Authorization: Bearer YOUR_KEY"

Error codes

All error responses follow this format:

{
  "success": false,
  "error": {
    "code": "validation_error",
    "message": "Human readable error message",
    "details": { "field": "languages.1.title" }
  }
}
CodeHTTPMeaning
unauthorized401Missing or invalid API key
api_disabled503API disabled in configuration
https_required426Request must be made over HTTPS
rate_limited429Rate limit exceeded, or IP blocked after failed authentication
invalid_json400Invalid or missing JSON body
validation_error422Invalid field value (details in error.details)
conflict409Slug conflict: an article or category with this link already exists
not_found404Resource not found
method_not_allowed405HTTP method not supported for this endpoint
payload_too_large413Request body too large (limit: 10 MB)
internal_error500Internal server error

Rate limit: when exceeded, the 429 response includes a Retry-After header indicating how many seconds to wait before retrying. Each response also includes X-RateLimit-Limit and X-RateLimit-Remaining headers.

Python integration

For Python developers, the requests library makes it easy to interact with the API in just a few lines.

pip install requests
import requests

BASE = "https://your-shop.com/prestablog-api"
KEY = "YOUR_KEY"
headers = {"Authorization": f"Bearer {KEY}"}

# List articles
r = requests.get(f"{BASE}/articles", headers=headers, params={"lang": 1, "per_page": 10})
print(r.json())

# Create an article
r = requests.post(f"{BASE}/articles", headers=headers, json={
    "languages": {"1": {"title": "My article", "content": "<p>Content</p>"}},
    "categories": [1],
    "active": True
})
print(r.json())

# Upload an image from a local file
with open("image.jpg", "rb") as f:
    r = requests.post(f"{BASE}/articles/18/image", headers=headers, files={"file": f})
print(r.json())