Bootstrap and catalog
What the plan allows and how much is left, plus the curated template gallery and module library the editor browses.
All endpoints on this page require Authorization: Bearer {session_token} from the session endpoint and the embedded headers. They are limited to 120 requests per minute per session.
Bootstrap
What this plugin's plan allows and what the plugin is configured to show, in one round trip.
GET /public/plugin/v1/bootstrap
Authorization: Bearer mep_…curation is what the plugin is configured to expose: categories set by MailEditor, blocks, AI and stock providers set by the owner. features is what the plan includes. They are reported separately so the editor can tell "your administrator turned this off" from "your plan does not include this". Blocks are the exception: curation.blocks.enabled is already intersected with the plan.
Quotas are spent and subscriptions change during a session, so re-fetch this rather than caching it for the life of the token.
200
{
"message": "Bootstrap retrieved successfully",
"result": {
"bootstrap": {
"plugin": { "plugin_id": "9f3c…", "name": "Acme Editor", "version": "1.0.0" },
"mode": "b",
"tier": "development",
"subscription": { "plan": "Free", "status": "active", "renews_at": null },
"features": ["html_editor", "ai_generations"],
"entitlements": [ "…every allowance…" ],
"curation": {
"templates": { "is_filtered": false, "categories": [] },
"modules": { "is_filtered": false, "categories": [] },
"blocks": { "blocks": [], "enabled": [], "hidden": [], "restricted": [], "total": 14, "is_customized": false },
"ai": { "is_available": true, "providers": ["openai"] },
"stock": { "is_available": true, "providers": [{ "value": "unsplash", "label": "Unsplash" }] },
"logo": null,
"theme": null
},
"quotas": [
{
"feature": "ai_generations",
"name": "AI Generations (BYOK)",
"group": "AI",
"kind": "count",
"is_enabled": true,
"limit": "unlimited",
"limit_value": null,
"used": 120,
"remaining": null,
"is_unlimited": true,
"resets_at": null
}
],
"enforced": true
}
}
}| Field | Notes |
|---|---|
features | The feature ids the plan includes |
entitlements | Every allowance in full, including disabled ones, so you can grey out rather than hide |
quotas | Only the countable allowances. A switch such as html_editor never appears here |
quotas[].limit | The plan's own wording, such as "500" or "30 GB" |
quotas[].limit_value | Parsed, for arithmetic. Bytes for sizes. null means uncapped |
subscription | null when the plugin is on no plan |
tier | production when the domain is verified, otherwise development |
enforced | Whether requests past remaining: 0 are refused. See below |
curation | What the plugin is configured to show: the categories MailEditor set for the plugin, plus blocks, AI and stock availability, logo and theme as set in the dashboard |
users counts end users who have saved work: distinct external_user_id values across the plugin's templates. Someone who never saves takes no seat, and anonymous sessions never do. image_storage counts only bytes on MailEditor storage; uploads to your own bucket are not counted. ai_generations is unlimited on every plan, because generations run on the provider key you attach.
curation
| Field | Meaning |
|---|---|
blocks | The block palette as configured on the Basic Block Management tab |
blocks.enabled | Already intersected with the plan. Render exactly these |
blocks.blocks | Every block with is_enabled (owner), is_entitled (plan) and is_available (both) |
templates.categories, modules.categories | The categories configured for the plugin, in order |
is_filtered | false means no selection, so every category is available and categories is []. Branch on is_filtered, not on the array being empty |
ai.is_available | Whether this plugin has an AI provider key |
ai.providers | Which providers are configured. Names only |
stock.is_available | Whether this plugin has any stock provider key. false means the editor shows no stock library |
stock.providers | The providers to offer, each { value, label }. Pass value as provider on the stock endpoints |
logo | The owner's logo object, or null |
theme | The owner's editor theme as { primary, secondary, foreground, background, font }. The colors are hex strings or null; font is a Google Fonts family name or null. null when nothing is set |
enforced
true means a request past remaining: 0 returns 402, and a plugin with no active subscription is entitled to nothing. When it is false, usage is reported but nothing is refused. Read this field rather than assuming.
Catalog
The following endpoints browse the template gallery and module library, narrowed to the categories configured for the plugin.
- Filters narrow, never widen. Naming a category the plugin has not selected returns nothing.
result.filterslists only curated categories, so the editor never renders a facet that yields an empty list.
The editor calls these modules; the API paths use components.
The gallery endpoints require the template_gallery_access plan feature and the component endpoints require module_library. Without the feature they return 402 feature_not_in_plan, and the editor disables the corresponding start option or sidebar tab.
Browse the template gallery
GET /public/plugin/v1/templates?search=launch&category=Product&per_page=15| Query | Notes |
|---|---|
search | Matches template name |
category, industry, season | By name. All clears. Always intersected with the plugin's curation |
type | premium or free |
sort_by, per_page | Default 15 per page |
200
{
"message": "Template Fetch Successfully",
"result": {
"templates": {
"data": [
{
"id": 41,
"name": "Product Launch",
"slug": "product-launch",
"description": null,
"meta_description": null,
"is_premium": false,
"thumbnail": "https://…",
"thumbnail_mobile": "https://…",
"created_at": "2026-08-13T09:14:22.000000Z",
"avg_rating": 4.5,
"rating_count": 12,
"categories": [{ "id": 3, "name": "Product", "slug": "product" }],
"industries": [],
"tags": []
}
],
"links": { "first": "…", "last": "…", "prev": null, "next": null },
"meta": { "current_page": 1, "per_page": 15, "total": 1 }
},
"filters": { "categories": ["All", "Product"] }
}
}Premium templates are listed and flagged with is_premium rather than hidden.
Browse the component library
GET /public/plugin/v1/components?category=Checkout&per_page=10200. total_count is the plugin's visible total. Module HTML is inlined.
{
"message": "Components retrieved successfully",
"result": {
"total_count": 8,
"components": {
"data": [
{
"id": 7,
"name": "Cart Summary",
"thumbnail": "https://…",
"is_featured": false,
"html": "<table>…</table>",
"css": null,
"category": [{ "id": 4, "name": "Checkout", "slug": "checkout" }]
}
],
"links": {},
"meta": {}
},
"filters": { "category": ["Featured", "Checkout"] }
}
}Template categories
GET /public/plugin/v1/template-categoriesReturns the owner's selection when the plugin is curated, otherwise every category.
{
"message": "Template categories retrieved successfully",
"result": {
"categories": [
{ "id": 3, "name": "Product", "slug": "product", "description": null, "templates_count": 12 }
]
}
}templates_count is what that category will yield. A selected but empty category is still returned with a count of 0.
Component categories
GET /public/plugin/v1/component-categories200 with counts scoped to the plugin:
{
"message": "Categories fetched successfully",
"result": {
"all_components_count": 8,
"features_components_count": 2,
"categories": [
{ "id": 4, "name": "Checkout", "slug": null, "components_count": 8, "class": "ComponentCategory", "meta_title": null, "meta_description": null, "description": null }
]
}
}
.png)