Skip to content

Headless API

The Headless API gives you full programmatic access to templates, media, rendering, and all Cloud features — without the visual editor. Build custom workflows, batch operations, CI/CD pipelines, and integrations.

Authentication

Use direct authentication for server-side access:

js
import { createSdkAuthManager, ApiClient } from '@templatical/core/cloud';

const auth = createSdkAuthManager({
  mode: 'direct',
  clientId: process.env.TEMPLATICAL_CLIENT_ID,
  clientSecret: process.env.TEMPLATICAL_CLIENT_SECRET,
  tenant: 'tenant-slug',
});

await auth.initialize();
const api = new ApiClient(auth);

WARNING

Direct authentication should only be used in server-side code. Never expose credentials in the browser.

Templates

Create

js
const template = await api.createTemplate({
  blocks: [],
  settings: { width: 600, backgroundColor: '#ffffff', fontFamily: 'Arial' },
});

Read

js
const template = await api.getTemplate('template-id');

Update

js
const updated = await api.updateTemplate('template-id', {
  blocks: modifiedBlocks,
  settings: template.content.settings,
});

Delete

js
await api.deleteTemplate('template-id');

Export

js
const { html, mjml } = await api.exportTemplate('template-id');

With custom fonts:

js
const { html } = await api.exportTemplate('template-id', {
  customFonts: [{ name: 'Inter', url: 'https://fonts.googleapis.com/css2?family=Inter' }],
  defaultFallback: 'Arial, sans-serif',
});

Versions

js
// List versions (each carries its content)
const versions = await api.getVersions('template-id');

// Fetch one version's content
const version = await api.getVersion('template-id', 'version-id');

// Record a version
await api.createVersion('template-id', content);

// Restore a version — append-only, so this adds an entry
const restored = await api.restoreVersion('template-id', 'version-id');

Comments

js
// List comments
const comments = await api.getComments('template-id');

// Add a comment
const comment = await api.createComment('template-id', {
  body: 'This section needs a stronger CTA',
  block_id: 'block-uuid',
  user_id: 'user-123',
  user_name: 'Jane Smith',
  user_signature: 'hmac-signature',
});

// Resolve a comment
await api.resolveComment('template-id', 'comment-id', {
  user_id: 'user-123',
  user_name: 'Jane Smith',
  user_signature: 'hmac-signature',
});

Saved Blocks

js
// List saved blocks
const savedBlocks = await api.listModules();

// Create a saved block
const savedBlock = await api.createModule({
  name: 'Product Card',
  content: sectionContent,
});

// Delete a saved block
await api.deleteModule('saved-block-id');

TIP

The REST routes and ApiClient method names keep their original module wording for backward compatibility — only the feature's name changed. For the editor-side feature and the storage-provider interface, see Saved Blocks.

Test Emails

js
await api.sendTestEmail('template-id', {
  recipient: '[email protected]',
  html: '<html>...</html>',
  allowed_emails: ['[email protected]'],
  signature: 'hmac-signature',
});

Plan Configuration

js
const config = await api.fetchConfig();
console.log(config.features); // Available features for this plan

API Routes Reference

All routes are scoped to a project and tenant:

RouteMethodDescription
configGETGet plan configuration
broadcasting/authPOSTAuthenticate WebSocket connection
templatesPOSTCreate template
templates/import/from-beefreePOSTImport BeeFree template
templates/import/from-unlayerPOSTImport Unlayer template
templates/{id}GETGet template
templates/{id}PUTUpdate template
templates/{id}DELETEDelete template
templates/{id}/exportPOSTExport to HTML/MJML
templates/{id}/send-test-emailPOSTSend test email
templates/{id}/versionsGETList versions
templates/{id}/versionsPOSTRecord version
templates/{id}/versions/{id}GETGet one version
templates/{id}/versions/{id}/restorePOSTRestore version
templates/{id}/commentsGETList comments
templates/{id}/commentsPOSTCreate comment
templates/{id}/comments/{id}PUTUpdate comment
templates/{id}/comments/{id}DELETEDelete comment
templates/{id}/comments/{id}/resolvePOSTResolve comment
templates/{id}/ai/generatePOSTAI content generation
templates/{id}/ai/conversation-messagesGETAI conversation history
templates/{id}/ai/suggestionsPOSTAI prompt suggestions
templates/{id}/ai/rewrite-textPOSTAI text rewrite
templates/{id}/ai/scorePOSTTemplate quality scoring
templates/{id}/ai/fix-findingPOSTAI fix scoring finding
templates/{id}/ai/generate-from-designPOSTDesign-to-template conversion
saved-modulesGETList saved blocks
saved-modulesPOSTCreate saved block
saved-modules/{id}PUTUpdate saved block
saved-modules/{id}DELETEDelete saved block
media/browseGETBrowse media
media/uploadPOSTUpload media
media/deletePOSTDelete media
media/movePOSTMove media to folder
media/check-usagePOSTCheck media usage in templates
media/frequently-usedGETGet frequently used media
media/import-from-urlPOSTImport media from URL
media/{id}PUTUpdate media metadata
media/{id}/replacePOSTReplace media file
media-foldersGETList media folders
media-foldersPOSTCreate media folder
media-folders/{id}PUTRename media folder
media-folders/{id}DELETEDelete media folder