Blog endpoints sit under /api/brands/{brand}/blogs/ with brandAccess middleware. Authenticate with EF-Access-Key.
List Blogs
GET /api/brands/{brand}/blogs
Results per page (1–100, default: 25)
newest, oldest, created_at, updated_at
curl https://app.elasticfunnels.io/api/brands/{brand_id}/blogs \
-H "EF-Access-Key: your_api_key_here"
{
"current_page" : 1 ,
"data" : [
{
"id" : 2 ,
"name" : "Health Tips Blog" ,
"slug" : "health-tips" ,
"domain_id" : 7 ,
"status" : "published" ,
"comments_enabled" : false ,
"article_url_pattern" : "slug_only" ,
"created_at" : "2024-10-01T00:00:00.000000Z"
}
],
"per_page" : 25 ,
"total" : 2 ,
"last_page" : 1
}
List Blogs (Unpaginated)
GET /api/brands/{brand}/blogs/all
Returns { id, name } for all blogs with a saved config — useful for dropdowns.
Get Blog
GET /api/brands/{brand}/blogs/{blog}
{
"id" : 2 ,
"name" : "Health Tips Blog" ,
"domain_id" : 7 ,
"brand_template_id" : null ,
"slug" : "health-tips" ,
"article_url_pattern" : "slug_only" ,
"article_url_segment" : null ,
"category_url_segment" : "category" ,
"tag_url_segment" : "tag" ,
"search_url_segment" : "search" ,
"comments_enabled" : false ,
"comments_require_email_confirmation" : false ,
"seo_settings" : [],
"template" : null
}
Create Blog
POST /api/brands/{brand}/blogs
ID of the domain this blog lives on
URL slug (kebab-case, max 255). Must be unique per brand + domain.
ID of the template to apply (context=blog)
slug_only, segment, or category
URL prefix for articles (max 64)
URL prefix for category pages (default: category, max 64)
URL prefix for tag pages (default: tag, max 64)
URL prefix for search results (default: search, max 64)
Enable comment system for articles
Require email confirmation before comments appear
SEO metadata object (meta title, description, OG tags, Twitter card fields)
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/blogs \
-H "EF-Access-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Health Tips Blog",
"domain_id": 7,
"slug": "health-tips",
"article_url_pattern": "slug_only"
}'
200 Created
422 Missing name
422 Duplicate slug
{
"blog" : {
"id" : 2 ,
"name" : "Health Tips Blog" ,
"slug" : "health-tips" ,
"domain_id" : 7 ,
"comments_enabled" : false ,
"brand_id" : 42 ,
"created_at" : "2024-12-11T10:00:00.000000Z"
}
}
name is always required — even on PUT/PATCH updates. A partial update that omits name will return a 422 validation error.
Update Blog
PUT /api/brands/{brand}/blogs/{blog}
Same body as Create. name is still required.
Delete Blog
DELETE /api/brands/{brand}/blogs/{blog}
{ "blog" : { /* soft-deleted blog object */ } }
Clone Blog
Creates a copy of a blog within the same brand.
POST /api/brands/{brand}/blogs/{blog}/clone
Name for the cloned blog (max 255). Defaults to "<original name> (Copy)" if omitted.
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/blogs/2/clone \
-H "EF-Access-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"title": "Health Tips Blog v2"}'
{
"id" : 3 ,
"blog" : { /* cloned BrandBlog model */ }
}
Export Blogs
POST /api/brands/{brand}/blogs/export
Filter conditions (same as list query params)
Limit export to specific blog IDs
{
"success" : true ,
"message" : "Export started. You will receive an email when it is ready."
}
Blog Categories
List Categories
GET /api/brands/{brand}/blogs/{blog}/categories
[
{
"id" : 1 ,
"blog_id" : 2 ,
"name" : "Nutrition" ,
"slug" : "nutrition" ,
"hero_image" : null ,
"seo_settings" : {}
}
]
Create Category
POST /api/brands/{brand}/blogs/{blog}/categories
URL slug. Auto-generated from name if omitted; appends numeric suffix on collision.
Image URL (max 2048 chars)
SEO metadata (meta title, description, OG tags, Twitter card)
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/blogs/2/categories \
-H "EF-Access-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "Nutrition", "slug": "nutrition"}'
{
"id" : 1 ,
"blog_id" : 2 ,
"name" : "Nutrition" ,
"slug" : "nutrition"
}
Update Category
PUT /api/brands/{brand}/blogs/{blog}/categories/{category}
Same body as Create (all fields optional on update).
Delete Category
DELETE /api/brands/{brand}/blogs/{blog}/categories/{category}
Notes
Blog slugs must be globally unique per brand_id + domain_id combination
The clone endpoint copies the blog’s config, html, css, and interactions to the new blog. Slug uniqueness is handled automatically with a numeric suffix
The builder (GET/POST .../blogs/{blog}/builder) and articles CRUD endpoints are managed through the page builder and article editor controllers respectively