This is the full developer documentation for Templated # Get Account Information > Learn how to retrieve your account information using the Templated API. This endpoint allows you to retrieve information about your account, including your email, name, API usage statistics, and quota details. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to get your account information: ENDPOINT ```js GET /v1/account ``` ```js fetch('https://api.templated.io/v1/account', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The endpoint returns a JSON object with your account details. ```json { "email": "user@example.com", "name": "John Doe", "apiUsage": 5400, "apiQuota": 10000, "usagePercentage": 54, "plan": "Scale" } ``` ### Response Fields [Section titled “Response Fields”](#response-fields) email `string`\ The email address associated with your account. name `string`\ Your account name. apiUsage `integer`\ The current number of API credits you’ve used. apiQuota `integer`\ Your total API credits quota (monthly if you have a paid plan). usagePercentage `integer`\ The percentage of your API quota that has been used. plan `string`\ Your current plan. # Authentication Templated uses API keys to allow access to the API.\ To get started, create a free account [here](https://app.templated.io/signup).\ Once logged in, you can find your API key in the [API Key](https://app.templated.io/api-key) tab of your dashboard.\ This API key will give you full access to all API endpoints. ## How to find your API key [Section titled “How to find your API key”](#how-to-find-your-api-key) Follow these simple steps to locate your API key in the Templated dashboard: 1. **Log in to your Templated account** Go to [app.templated.io](https://app.templated.io) and sign in with your credentials. 2. **Click on “API Key” in the sidebar** In the left sidebar navigation, look for the **API Key** menu item and click on it. ![Click on API Key in the sidebar](/images/docs/find-api-key-step1.png) 3. **Copy your API Key** Your API key will be displayed on the page. Click the **copy button** to copy it to your clipboard. ![Copy your API Key](/images/docs/find-api-key-step2.png) Keep Your API Key Secure Your API key provides full access to your account. Never share it publicly or commit it to version control. Store it securely in environment variables. ## Authorization Header [Section titled “Authorization Header”](#authorization-header) The API expects the API key to be included in **all** requests in the `Authorization` header as a `Bearer` token: AUTHORIZATION HEADER ```php Authorization: Bearer API_KEY ``` ## Base URL [Section titled “Base URL”](#base-url) This is the base URL that all requests to the API should be made to: BASE URL ```php https://api.templated.io ``` In the next steps we will see sample code to create, retrieve and list renders and templates usign the API. # Advanced Features > Learn advanced techniques for customizing and enhancing your embedded editor integration. Take your embedded editor integration to the next level with these advanced features and customization options. ## URL Parameters for Customization [Section titled “URL Parameters for Customization”](#url-parameters-for-customization) The embedded editor supports numerous URL parameters to customize behavior and appearance. These parameters can be added to your embed URL to control the editor’s functionality. ### Basic Configuration [Section titled “Basic Configuration”](#basic-configuration) embed `string` (required)\ Your embed configuration ID from the dashboard. preview `boolean`\ Launch in preview mode (canvas-only). Default: false. zoom `number`\ Initial zoom level (10-100). 50 equals 100% scale. Auto-calculated if not set. clone `boolean`\ Create a clone instead of editing the original template. Default: false. copy `boolean`\ Alternative to clone parameter. Default: false. ### Permission Controls [Section titled “Permission Controls”](#permission-controls) allow-rename `boolean`\ Allow users to rename templates. Default: true. allow-save `boolean`\ Enable the save functionality. Default: true. allow-download `boolean`\ Enable template download. Default: true. allow-resize `boolean`\ Allow users to resize the template dimensions. Default: false. allow-create-template `boolean`\ Enable creating new templates from the editor. Default: true. ### Layer Controls [Section titled “Layer Controls”](#layer-controls) allow-layer-move `boolean`\ Allow moving layers around the canvas. Default: false. allow-layer-resize `boolean`\ Enable resizing of individual layers. Default: false. allow-layer-select `boolean`\ Allow selecting layers. Default: false. allow-layer-unlock `boolean`\ Allow users to unlock locked layers. Default: false. allow-layer-rename `boolean`\ Enable renaming of layers. Default: false. allow-text-edition `boolean`\ Allow double-click text editing. Default: false. ### UI Customization [Section titled “UI Customization”](#ui-customization) hide-sidebar `boolean`\ Hide the left sidebar panel. Default: false. hide-header `boolean`\ Hide the top header bar. Default: false. hide-layers-panel `boolean`\ Hide the layers panel. Default: false. hide-language-toggle `boolean`\ Hide the language switcher. Default: false. ### Data and Content [Section titled “Data and Content”](#data-and-content) metadata `string`\ Base64-encoded JSON with custom metadata for webhooks. layers `string`\ Base64-encoded JSON with initial layer data. folder `string`\ Limit template selection to a specific folder ID. image-url `string`\ URL of an image to load as background or layer. w `number`\ Custom template width in pixels. h `number`\ Custom template height in pixels. ### Integration Options [Section titled “Integration Options”](#integration-options) webhook-url `string`\ Override the default webhook URL for this session. external-id `string`\ Session identifier that tags all created content (templates, uploads, fonts, renders) and enables persistent sessions. move-to-folder `string`\ Automatically move saved templates to this folder ID. load-uploads `boolean`\ Load user uploads in the assets panel. Default: false. launch-mode `string`\ Control how the editor launches. Options: ‘account’, ‘gallery’, ‘blank’. ### Example URL with Multiple Parameters [Section titled “Example URL with Multiple Parameters”](#example-url-with-multiple-parameters) Fully Customized Embed ```html ``` ## Custom Metadata [Section titled “Custom Metadata”](#custom-metadata) Pass custom data through the embed that will be sent to your webhooks, enabling you to track user context and trigger specific workflows. ### Encoding Metadata [Section titled “Encoding Metadata”](#encoding-metadata) Metadata must be base64-encoded JSON and passed as a URL parameter: * JavaScript Encoding Metadata ```js // Your custom metadata const metadata = { userId: "user-123", projectId: "project-456", clientId: "client-789", workflowType: "marketing_campaign", campaignId: "campaign-001" }; // Encode as base64 const encodedMetadata = btoa(JSON.stringify(metadata)); // Create embed URL with metadata const embedUrl = `https://app.templated.io/editor?embed=${configId}&metadata=${encodedMetadata}`; // Update embed element document.getElementById('editor-embed').src = embedUrl; ``` * Python Encoding Metadata in Python ```python import json import base64 # Your custom metadata metadata = { "userId": "user-123", "projectId": "project-456", "clientId": "client-789", "workflowType": "marketing_campaign", "campaignId": "campaign-001" } # Encode as base64 encoded_metadata = base64.b64encode( json.dumps(metadata).encode('utf-8') ).decode('utf-8') # Create embed URL embed_url = f"https://app.templated.io/editor?embed={config_id}&metadata={encoded_metadata}" ``` * PHP Encoding Metadata in PHP ```php 'user-123', 'projectId' => 'project-456', 'clientId' => 'client-789', 'workflowType' => 'marketing_campaign', 'campaignId' => 'campaign-001' ]; // Encode as base64 $encodedMetadata = base64_encode(json_encode($metadata)); // Create embed URL $embedUrl = "https://app.templated.io/editor?embed={$configId}&metadata={$encodedMetadata}"; ?> ``` * React Encoding Metadata in React ```jsx import React, { useState, useEffect } from 'react'; function TemplateEmbed({ configId, user, project }) { const [embedUrl, setEmbedUrl] = useState(''); useEffect(() => { // Your custom metadata const metadata = { userId: user.id, projectId: project.id, clientId: user.clientId, workflowType: "marketing_campaign", campaignId: project.campaignId, timestamp: new Date().toISOString() }; // Encode as base64 const encodedMetadata = btoa(JSON.stringify(metadata)); // Create embed URL with metadata const url = `https://app.templated.io/editor?embed=${configId}&metadata=${encodedMetadata}`; setEmbedUrl(url); }, [configId, user, project]); return ( `; document.body.appendChild(modal); } // Alternative: Edit render with custom callback function editRenderWithCallback(renderId, onSave) { const metadata = { renderId: renderId, callback: 'custom', onSave: onSave.toString() // Pass callback function }; const encodedMetadata = btoa(JSON.stringify(metadata)); const embedUrl = `https://app.templated.io/editor?embed=YOUR_CONFIG_ID&metadata=${encodedMetadata}`; return embedUrl; } ``` * React React Render Editor ```jsx import React, { useState, useCallback } from 'react'; function RenderEditor({ renderId, userId, configId, onSave, onClose }) { const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const embedUrl = React.useMemo(() => { const metadata = { userId: userId, renderId: renderId, mode: 'edit_render', timestamp: new Date().toISOString() }; const encodedMetadata = btoa(JSON.stringify(metadata)); return `https://app.templated.io/editor?embed=${configId}&metadata=${encodedMetadata}`; }, [renderId, userId, configId]); const handleIframeLoad = () => { setIsLoading(false); }; const handleIframeError = () => { setIsLoading(false); setError('Failed to load editor'); }; return (
e.stopPropagation()}>

Edit Design

{isLoading && (

Loading editor...

)} {error && (

{error}

)} ``` ### URL parameters [Section titled “URL parameters”](#url-parameters) #### Form Configuration [Section titled “Form Configuration”](#form-configuration) * `form-panel-position` (left|right) — form panel position, default `right` Shared parameters All Preview Mode URL parameters also work in Form Mode — including `zoom`, `layers`, `metadata`, `clone`, `allow-*`, `hide-*`, and integration options. The download button visibility and allowed formats are controlled by the existing `allow-download` parameter and the **Download Formats** setting in your embed configuration dashboard. See [URL Parameters Reference](/docs/embed/url-parameters/). Example with flags: ```html ``` ## Layer visibility [Section titled “Layer visibility”](#layer-visibility) Lock layers in the editor to hide them from the form.\ Unlocked layers automatically appear as form fields.\ This lets you control exactly which layers end-users can customize. ## Layer types [Section titled “Layer types”](#layer-types) Each layer type renders a different set of form controls: | Layer type | Form controls | | ---------- | --------------------------------------- | | Text | Text input + color picker | | Image | URL input | | Shape | Fill color picker + stroke color picker | | QR Code | Text input for data | | Barcode | Text input for data | | Rating | Number input | ## Runtime control (postMessage) [Section titled “Runtime control (postMessage)”](#runtime-control-postmessage) After the iframe loads, you can control Form Mode at runtime using `postMessage`. The editor will also send events back. ### Messages you can send to the editor [Section titled “Messages you can send to the editor”](#messages-you-can-send-to-the-editor) Parent → Editor ```js // Toggle form mode on or off iframe.contentWindow.postMessage({ type: 'SET_FORM_MODE', enabled: true }, '*'); // Change the form panel position iframe.contentWindow.postMessage({ type: 'SET_FORM_PANEL_POSITION', position: 'left' // 'left' | 'right' }, '*'); ``` ### Events the editor sends back [Section titled “Events the editor sends back”](#events-the-editor-sends-back) Editor → Parent ```js window.addEventListener('message', (event) => { // Optional: verify origin: if (event.origin !== 'https://app.templated.io') return; const msg = event.data; switch (msg?.type) { // Form mode toggled case 'FORM_MODE_UPDATED': console.log('Form mode:', msg.enabled, 'Success:', msg.success); break; // Panel position changed case 'FORM_PANEL_POSITION_UPDATED': console.log('Panel position:', msg.position, 'Success:', msg.success); break; // A form field value changed case 'FORM_VALUES_CHANGED': // msg.data contains { layerName: { prop: value } } console.log('Form values changed:', msg.data); break; // User clicked the render button in the form case 'FORM_RENDER_REQUESTED': console.log('Render requested:', msg.format, msg.templateId); break; } }); ``` ## Mobile [Section titled “Mobile”](#mobile) On screens narrower than 1024px, the form panel automatically stacks below the canvas for a mobile-friendly layout. ## Complete example [Section titled “Complete example”](#complete-example) Comprehensive working example ```html
``` ## See also [Section titled “See also”](#see-also) * [Preview Mode ](/docs/embed/preview-mode/) * [Advanced ](/docs/embed/advanced/) # The Embedded Editor > Learn how to integrate Templated's editor directly into your website or application. The Embedded Editor allows you to integrate Templated’s powerful template editing capabilities directly into your website or application.\ Your users can create, edit, and customize templates without leaving your platform.\ You can check a demo [here](https://templated.io/embed-image-editor-in-your-app/) ## Key Features [Section titled “Key Features”](#key-features) Simple Integration Embed the editor with a simple HTML embed tag. No complex setup required. Customizable Customize colors, logos, permissions, and behavior to match your brand. Launch Modes Start with your templates, template gallery, or blank canvas. Webhook Receive real-time notifications when users save or download templates. ## How to Embed the Editor [Section titled “How to Embed the Editor”](#how-to-embed-the-editor) 1. **Navigate to the Embedded Editor settings** Log in to your Templated dashboard and click on **Embedded Editor** in the sidebar. ![Click on Embedded Editor in the sidebar](/images/docs/embed-step1-sidebar.png) 2. **Configure your embed settings** Set up your domain, branding, permissions, and launch behavior using the configuration panels. ![Configure your embed settings](/images/docs/embed-step2-settings.png) 3. **Copy the embed code** Click the **Copy code** button to copy the HTML `` tag customized for your configuration. ![Copy the embed code](/images/docs/embed-step3-copycode.png) 4. **Add to your website or app** Paste the embed code wherever you want the editor to appear. 5. **Users start editing** Your users can now create and edit templates directly in your platform. ## Basic Integration [Section titled “Basic Integration”](#basic-integration) The simplest way to embed the editor is with an HTML embed tag: ```html ``` ## Advanced Options [Section titled “Advanced Options”](#advanced-options) The embedded editor supports many advanced features through URL parameters: * **Custom metadata** - Pass user data to your webhooks * **Specific template launching** - Start with a particular template * **Layer data injection** - Pre-populate template content * **Clone functionality** - Create template copies without affecting originals * **Render editing** - Allow users to edit existing renders * **Permission controls** - Fine-tune what users can and cannot do * **UI customization** - Hide or show specific interface elements [URL Parameters Reference ](/docs/embed/url-parameters/)Complete reference of all available URL parameters for customization. ## Use Cases [Section titled “Use Cases”](#use-cases) SaaS Platforms Offer template editing as a feature in your software platform. Marketing Agencies Let clients edit templates directly from your client portal. E-commerce Allow customers to customize product designs and marketing materials. Education Enable students to create presentations and educational materials. News publishers Allow users to create, edit and automate your news images. Automation software Create software that allows users to create, edit and automate their content. ## Getting Started [Section titled “Getting Started”](#getting-started) Ready to integrate the Embedded Editor? Follow these steps: 1. [Set up your embed configuration](/docs/embed/configuration/) 2. [Learn about launch modes](/docs/embed/launch-modes/) 3. [Explore URL parameters](/docs/embed/url-parameters/) 4. [Use Preview Mode](/docs/embed/preview-mode/) 5. [Implement webhook integration](/docs/embed/webhooks/) 6. [Explore advanced features](/docs/embed/advanced/) ## Requirements [Section titled “Requirements”](#requirements) * **For development:** Works on localhost and local environments * **For production:** Requires a [Scale plan](https://templated.io/pricing) subscription * **Domain verification:** Your domain must be configured in the embed settings\\ ## Need Help? [Section titled “Need Help?”](#need-help) We’re glad to assist you integrating the editor to your website or application.\ If you need assistance or have questions, please contact our support team through the **chat widget** in your dashboard or via email at # Launch Modes > Learn about different ways to initialize the embedded editor for your users. Launch modes determine how the embedded editor initializes when your users first access it. Choose the mode that best fits your use case and user workflow. ## 1. Account Templates [Section titled “1. Account Templates”](#1-account-templates) Launch with your account templates, giving users access to your professionally designed templates.\ When using account templates, choose how users interact with your templates: ### → Create Copy (Default) [Section titled “→ Create Copy (Default)”](#-create-copy-default) Creates a new template from the selected one. Changes are saved as a new template in your account. ### → Create Clone [Section titled “→ Create Clone”](#-create-clone) Creates a clone that doesn’t appear in your dashboard. Perfect for temporary edits or user-specific variations. ### → Edit Original [Section titled “→ Edit Original”](#-edit-original) Directly edit the selected template. Changes are saved to the original template. This is the default mode. ## 2. Template Gallery [Section titled “2. Template Gallery”](#2-template-gallery) Launch with Templated’s public template gallery, giving users access to hundreds of professionally designed templates. ## 3. User Renders [Section titled “3. User Renders”](#3-user-renders) Launch with the user’s previously rendered designs, giving users access to their previously rendered designs. ## 4. Blank Template [Section titled “4. Blank Template”](#4-blank-template) Start with a completely blank canvas for custom designs. Launch Mode Selection Tips Consider your users’ experience level, your content strategy, and integration context when choosing launch modes. You can always change modes or offer multiple entry points. ## Other ways to launch the editor [Section titled “Other ways to launch the editor”](#other-ways-to-launch-the-editor) Launch directly into editing a specific template or render, bypassing the selection modal entirely. ### Edit specific template [Section titled “Edit specific template”](#edit-specific-template) Launch directly into editing a specific template, bypassing the selection modal entirely. Launch Specific Template ```js // Pass the template ID as a parameter to the editor ``` ### Clone specific template [Section titled “Clone specific template”](#clone-specific-template) Create a clone of a specific template: Clone Specific Template ```js // Pass the template ID as a parameter to the editor and add the clone parameter as true ``` ### Edit specific render [Section titled “Edit specific render”](#edit-specific-render) Allow users to edit an existing render, automatically creating a clone template: Edit Existing Render ```js // Pass the render ID as a parameter to the editor ``` ## Dynamic Launch Modes [Section titled “Dynamic Launch Modes”](#dynamic-launch-modes) Choose launch modes dynamically based on user context: * JavaScript Dynamic launch mode selection ```js function generateEmbedUrl(embedId, templateId) { const baseUrl = `https://app.templated.io/editor?embed=${embedId}`; // Specific use cases if (templateId) { return `https://app.templated.io/editor/${templateId}?embed=${embedId}`; } return baseUrl; } // Update embed src dynamically const embedElement = document.querySelector('#template-editor'); embedElement.src = generateEmbedUrl(currentEmbedId, currentTemplateId); ``` * React React Component with Dynamic Mode ```jsx import React, { useMemo } from 'react'; function TemplateEditor({ embedId, templateId }) { const embedUrl = useMemo(() => { const baseUrl = `https://app.templated.io/editor?embed=${embedId}`; if (templateId) { return `https://app.templated.io/editor/${templateId}?embed=${embedId}`; } return baseUrl; }, [templateId, embedId]); return ( ); } ``` # Preview Mode > Canvas-only embedded editor with URL flags and runtime control via postMessage. The Preview Mode is a canvas-only version of the editor designed for fast, distraction-free embedding. It hides the editor UI and focuses on rendering and manipulating template content. You can configure the initial state via URL parameters and control behavior at runtime with `postMessage`. You can try a demo implementation [here](https://templated.io/test-preview.html). ## Enable Preview Mode [Section titled “Enable Preview Mode”](#enable-preview-mode) Use the preview base path: `/editor/preview/{TEMPLATE_ID}?embed={CONFIG_ID}`. Basic Preview Embed ```html ``` ### Optional URL parameters [Section titled “Optional URL parameters”](#optional-url-parameters) #### Basic Configuration [Section titled “Basic Configuration”](#basic-configuration) * `zoom` (10–100) – initial zoom level; `50` equals 100% scale * `clone` (true|false) – create a clone instead of editing original template * `layers` – base64-encoded JSON with initial layer data (see Advanced page) * `metadata` – base64-encoded JSON with custom metadata for webhooks * `page` (string) – show only a specific page by name or ID (hides all other pages) #### Layer Permissions [Section titled “Layer Permissions”](#layer-permissions) * `allow-layer-move` (true|false) – allow moving layers in preview * `allow-layer-resize` (true|false) – allow resizing layers in preview * `allow-layer-select` (true|false) – allow selecting layers * `allow-layer-unlock` (true|false) – allow unlocking locked layers * `allow-layer-rename` (true|false) – allow renaming layers * `allow-text-edition` (true|false) – allow double-click text editing in preview #### Template Permissions [Section titled “Template Permissions”](#template-permissions) * `allow-rename` (true|false) – allow renaming the template * `allow-save` (true|false) – enable save functionality * `allow-download` (true|false) – enable download functionality * `allow-resize` (true|false) – allow resizing template dimensions * `allow-create-template` (true|false) – enable creating new templates #### UI Customization [Section titled “UI Customization”](#ui-customization) * `hide-sidebar` (true|false) – hide the left sidebar panel * `hide-header` (true|false) – hide the top header bar * `hide-layers-panel` (true|false) – hide the layers panel * `hide-language-toggle` (true|false) – hide the language switcher #### Integration Options [Section titled “Integration Options”](#integration-options) * `webhook-url` (string) – override default webhook URL for this session * `external-id` (string) – session identifier for persistent uploads, fonts, and content tagging * `move-to-folder` (string) – automatically move saved templates to folder ID * `folder` (string) – limit template selection to specific folder ID * `image-url` (string) – URL of image to load as background or layer * `w` (number) – custom template width in pixels * `h` (number) – custom template height in pixels Example with flags: ```html ``` Layer data To pre-populate content, pass `layers` as a base64-encoded JSON. See [Advanced → Pre-populate Template Data](/docs/embed/advanced/#pre-populate-template-data). ## Runtime control (postMessage) [Section titled “Runtime control (postMessage)”](#runtime-control-postmessage) After the iframe loads, you can control Preview Mode without reloading using `postMessage`. The editor will also send status events back. ### Messages you can send to the editor [Section titled “Messages you can send to the editor”](#messages-you-can-send-to-the-editor) Parent → Editor ```js // Update layer values iframe.contentWindow.postMessage({ type: 'UPDATE_LAYERS', data: { 'headline': { text: 'New title', color: '#FF0000' }, 'hero-image': { image_url: 'https://example.com/image.jpg' } } }, '*'); // Update layer values with template background iframe.contentWindow.postMessage({ type: 'UPDATE_LAYERS', data: { background: '#0066CC', // Template-level background color layers: { 'headline': { text: 'New title', color: '#FF0000' }, 'hero-image': { image_url: 'https://example.com/image.jpg' } } } }, '*'); // Set zoom (10–100; 50 = 100% scale) iframe.contentWindow.postMessage({ type: 'SET_ZOOM', zoom: 60 }, '*'); // Toggle layer capabilities iframe.contentWindow.postMessage({ type: 'SET_ALLOW_LAYER_MOVE', allowLayerMove: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_LAYER_RESIZE', allowLayerResize: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_LAYER_UNLOCK', allowLayerUnlock: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_LAYER_RENAME', allowLayerRename: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_TEXT_EDITION', allowTextEdition: true }, '*'); // Toggle template capabilities iframe.contentWindow.postMessage({ type: 'SET_ALLOW_RENAME', allowRename: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_SAVE', allowSave: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_DOWNLOAD', allowDownload: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_RESIZE', allowResize: true }, '*'); iframe.contentWindow.postMessage({ type: 'SET_ALLOW_CREATE_TEMPLATE', allowCreateTemplate: true }, '*'); // Load a different template without reloading the iframe iframe.contentWindow.postMessage({ type: 'LOAD_TEMPLATE', templateId: 'tpl_123', clone: false }, '*'); // Save the current template iframe.contentWindow.postMessage({ type: 'SAVE' }, '*'); // Download the template (uses the format currently selected in the editor) iframe.contentWindow.postMessage({ type: 'DOWNLOAD' }, '*'); // Download with explicit format and page selection iframe.contentWindow.postMessage({ type: 'DOWNLOAD', format: 'pdf', // optional: 'jpg' | 'png' | 'pdf' | 'mp4' pages: 'all' // optional: 'all' (default) or comma-separated page ids e.g. '1,3' }, '*'); // Add a new layer iframe.contentWindow.postMessage({ type: 'ADD_LAYER', layer: { type: 'text', // required: 'text' | 'image' | 'video' | 'shape' | 'qr-code' name: 'my-text-layer', // optional, auto-generated if omitted x: 100, // optional, default: 0 y: 50, // optional, default: 0 width: 200, // optional, default: 100 height: 50, // optional, default: 100 text: 'Hello World', // for text layers fontSize: 24, // for text layers color: '#333333', // for text layers fontFamily: 'Arial', // for text layers page: 'page-1' // optional, defaults to current page } }, '*'); // Add an image layer iframe.contentWindow.postMessage({ type: 'ADD_LAYER', layer: { type: 'image', name: 'hero-image', src: 'https://example.com/image.jpg', x: 0, y: 0, width: 400, height: 300 } }, '*'); // Add a shape layer iframe.contentWindow.postMessage({ type: 'ADD_LAYER', layer: { type: 'shape', name: 'background-box', shapeType: 'rect', // 'rect' | 'circle' | 'ellipse' | 'line' fillColor: 'rgb(200,200,200)', strokeColor: 'rgb(0,0,0)', strokeWidth: 2, x: 50, y: 50, width: 300, height: 200 } }, '*'); // Remove a layer by name iframe.contentWindow.postMessage({ type: 'REMOVE_LAYER', name: 'my-text-layer', // layer name (required) page: 'page-1' // optional, limits search to specific page }, '*'); // Show only a specific page (hides all others) iframe.contentWindow.postMessage({ type: 'SET_PAGE', pageId: 'page-1' // page name or ID }, '*'); // Show all pages (restore multi-page view) iframe.contentWindow.postMessage({ type: 'SHOW_ALL_PAGES' }, '*'); // Get all layers (name and type only) iframe.contentWindow.postMessage({ type: 'GET_LAYERS' }, '*'); // Get all pages with their layers iframe.contentWindow.postMessage({ type: 'GET_PAGES' }, '*'); ``` ### Events the editor sends back [Section titled “Events the editor sends back”](#events-the-editor-sends-back) Editor → Parent ```js window.addEventListener('message', (event) => { // Optional: verify origin: if (event.origin !== 'https://app.templated.io') return; const msg = event.data; switch (msg?.type) { // Editor lifecycle case 'EDITOR_READY': // Editor initialized; safe to send UPDATE_LAYERS / SET_* messages break; // Template events case 'TEMPLATE_LOADED': // URL-based initial load completed; contains template details console.log('Loaded via URL:', msg.template); break; case 'TEMPLATE_LOADED_SUCCESS': // Successful LOAD_TEMPLATE postMessage console.log('Template switched:', msg.templateId); break; case 'TEMPLATE_LOAD_ERROR': console.error('Template load failed:', msg.error); break; case 'TEMPLATE_SAVED_SUCCESS': console.log('Template saved:', msg.templateId); break; case 'TEMPLATE_SAVE_ERROR': console.error('Template save failed:', msg.error); break; case 'TEMPLATE_DOWNLOADED_SUCCESS': // Successful DOWNLOAD postMessage console.log('Template downloaded:', msg.templateId, msg.format, msg.renderUrl); break; case 'TEMPLATE_DOWNLOAD_ERROR': console.error('Template download failed:', msg.error); break; // Layer events case 'LAYERS_UPDATED': // Acknowledges UPDATE_LAYERS break; case 'LAYER_UPDATE_ERROR': console.error('Layer update failed:', msg.error); break; case 'LAYER_ADDED': // Layer successfully added console.log('Layer added:', msg.layerId, msg.layerName); break; case 'ADD_LAYER_ERROR': console.error('Add layer failed:', msg.error); break; case 'LAYER_REMOVED': // Layer successfully removed console.log('Layer removed:', msg.layerName); break; case 'REMOVE_LAYER_ERROR': console.error('Remove layer failed:', msg.error); break; // Page events case 'PAGE_UPDATED': // Page visibility changed via SET_PAGE console.log('Page changed to:', msg.pageId, 'Success:', msg.success); break; case 'ALL_PAGES_SHOWN': // All pages are now visible via SHOW_ALL_PAGES console.log('All pages are now visible'); break; // Layer and page data retrieval case 'LAYERS_DATA': // Response to GET_LAYERS — flat list of { name, type } console.log('Layers:', msg.layers); break; case 'GET_LAYERS_ERROR': console.error('Failed to get layers:', msg.error); break; case 'PAGES_DATA': // Response to GET_PAGES — array of { page, layers: [{ name, type }] } console.log('Pages:', msg.pages); break; case 'GET_PAGES_ERROR': console.error('Failed to get pages:', msg.error); break; // Zoom events case 'ZOOM_UPDATED': console.log('Zoom now:', msg.zoom); // same 10–100 scale where 50 = 100% break; case 'ZOOM_UPDATE_ERROR': console.error('Zoom update failed:', msg.error); break; // Layer capability events case 'ALLOW_LAYER_MOVE_UPDATED': console.log('Layer move permission:', msg.allowLayerMove); break; case 'ALLOW_LAYER_RESIZE_UPDATED': console.log('Layer resize permission:', msg.allowLayerResize); break; case 'ALLOW_LAYER_UNLOCK_UPDATED': console.log('Layer unlock permission:', msg.allowLayerUnlock); break; case 'ALLOW_LAYER_RENAME_UPDATED': console.log('Layer rename permission:', msg.allowLayerRename); break; case 'ALLOW_TEXT_EDITION_UPDATED': console.log('Text edition permission:', msg.allowTextEdition); break; // Template capability events case 'ALLOW_RENAME_UPDATED': console.log('Rename permission:', msg.allowRename); break; case 'ALLOW_SAVE_UPDATED': console.log('Save permission:', msg.allowSave); break; case 'ALLOW_DOWNLOAD_UPDATED': console.log('Download permission:', msg.allowDownload); break; case 'ALLOW_RESIZE_UPDATED': console.log('Resize permission:', msg.allowResize); break; case 'ALLOW_CREATE_TEMPLATE_UPDATED': console.log('Create template permission:', msg.allowCreateTemplate); break; // Error events case 'ALLOW_LAYER_MOVE_UPDATE_ERROR': case 'ALLOW_LAYER_RESIZE_UPDATE_ERROR': case 'ALLOW_LAYER_UNLOCK_UPDATE_ERROR': case 'ALLOW_LAYER_RENAME_UPDATE_ERROR': case 'ALLOW_TEXT_EDITION_UPDATE_ERROR': case 'ALLOW_RENAME_UPDATE_ERROR': case 'ALLOW_SAVE_UPDATE_ERROR': case 'ALLOW_DOWNLOAD_UPDATE_ERROR': case 'ALLOW_RESIZE_UPDATE_ERROR': case 'ALLOW_CREATE_TEMPLATE_UPDATE_ERROR': case 'ADD_LAYER_ERROR': case 'REMOVE_LAYER_ERROR': console.error('Permission update failed:', msg.error); break; } }); ``` ## Recommended template switching strategy [Section titled “Recommended template switching strategy”](#recommended-template-switching-strategy) For best performance and reliable initialization: 1. Load the first template using the URL (`/editor/preview/{templateId}?embed=...`) so the editor initializes correctly. 2. Switch to other templates using the `LOAD_TEMPLATE` message to avoid iframe reloads and keep caches warm. ## Complete example [Section titled “Complete example”](#complete-example) Comprehensive working example ```html
``` ## See also [Section titled “See also”](#see-also) * [Pre-populate Template Data ](/docs/embed/advanced/#pre-populate-template-data) * [Launch Modes ](/docs/embed/launch-modes/) # URL Parameters Reference > Complete reference of all URL parameters available for customizing the embedded editor. This page provides a comprehensive reference of all URL parameters you can use to customize the embedded editor’s behavior and appearance. ## Required Parameters [Section titled “Required Parameters”](#required-parameters) embed `string`\ Your embed configuration ID from the dashboard. This parameter is required for all embeds. Basic Embed with Required Parameter ```html ``` ## Basic Configuration [Section titled “Basic Configuration”](#basic-configuration) clone `boolean`\ Create a clone instead of editing the original template. Default: `false` launch-mode `string`\ Control how the editor launches. Options: `'template-gallery'`, `'user-templates'`, `'user-renders'`, `'blank'` auto-save `boolean`\ Enable automatic saving of the template at regular intervals (every 15 seconds). Default: `false` ## Template and Content [Section titled “Template and Content”](#template-and-content) render `string`\ Load a specific render ID for editing (creates a template clone automatically) folder `string`\ Limit template selection to a specific folder ID image-url `string`\ URL of an image to load as background or layer w `number`\ Custom template width in pixels h `number`\ Custom template height in pixels layers `string`\ Base64-encoded JSON with initial layer data metadata `string`\ Base64-encoded JSON with custom metadata for webhooks ## Permission Controls [Section titled “Permission Controls”](#permission-controls) ### Template Permissions [Section titled “Template Permissions”](#template-permissions) allow-rename `boolean`\ Allow users to rename templates. Default: `true` allow-save `boolean`\ Enable the save functionality. Default: `true` allow-download `boolean`\ Enable template download. Default: `true` allow-resize `boolean`\ Allow users to resize the template dimensions. Default: `false` allow-create-template `boolean`\ Enable creating new templates from the editor. Default: `true` allow-template-selection `boolean`\ Show a Templates tab in the sidebar that opens a template selection modal, allowing users to browse and switch to a different template. Default: `false` allow-video `boolean`\ Enable video controls, including the timeline with play/pause and video settings (autoplay, loop, muted, show controls). Default: `false` ### Layer Permissions [Section titled “Layer Permissions”](#layer-permissions) allow-layer-move `boolean`\ Allow moving layers around the canvas. Default: `false` allow-layer-resize `boolean`\ Enable resizing of individual layers. Default: `false` allow-layer-select `boolean`\ Allow selecting layers. Default: `false` allow-layer-unlock `boolean`\ Allow users to unlock locked layers. Default: `false` allow-layer-rename `boolean`\ Enable renaming of layers. Default: `false` allow-text-edition `boolean`\ Allow double-click text editing. Default: `false` allow-edit-text-only `boolean`\ When enabled, only text layers are interactive (select, move, resize, edit text).\ All other layers (images, shapes, videos, etc.) are locked and cannot be selected or modified.\ Useful when you want end users to customize text content without affecting the template’s visual layout. Default: `false` ## UI Customization [Section titled “UI Customization”](#ui-customization) hide-sidebar `boolean`\ Hide the left sidebar panel. Default: `false` hide-header `boolean`\ Hide the top header bar. Default: `false` hide-layers-panel `boolean`\ Hide the layers panel. Default: `false` hide-save-button `boolean`\ Hide the Save button from the UI while still allowing saves to be triggered programmatically. Unlike `allow-save=false` (which disables saving entirely), this keeps the save functionality available via the `SAVE` postMessage event and the `⌘/Ctrl + S` keyboard shortcut, it only removes the visible button. Requires `allow-save=true`. Default: `false` hide-language-toggle `boolean`\ Hide the language switcher. Default: `false` language `string`\ Set the default language for the editor. Options: `'en'`, `'pt'`, `'es'`, `'fr'`, `'zh'`, `'cs'`, `'nl'`, `'de'`, `'ja'`. Default: `'en'` hide-canvas-background `boolean`\ Hide the dotted background pattern behind the canvas. Default: `false`\ The canvas background will be transparent and will have the same color as your parent page background color. page-layout-mode `string`\ Set the default layout mode for multi-page templates. Options: `'vertical'`, `'horizontal'`. Default: `'vertical'` page `string`\ Show only a specific page by its name or ID. Other pages will be hidden. Useful for displaying a single page from a multi-page template. hide-tabs `string`\ Comma-separated list of sidebar tab identifiers to hide. Available tabs: `text`, `images`, `videos`, `shapes`, `vectors`, `uploads`, `qr-code`, `barcode`, `rating`.\ Example: `&hide-tabs=barcode,qr-code,rating` will hide the Barcode, QR Code, and Rating tabs. zoom `number` (10-100)\ Initial zoom level. `50` equals 100% scale. Auto-calculated if not set. ## Integration Options [Section titled “Integration Options”](#integration-options) webhook-url `string`\ Override the default webhook URL for this session external-id `string`\ Session identifier that tags templates, uploads, fonts, and renders. Acts as a persistent session - when the editor is launched again with the same ID, previously uploaded assets and fonts will be available include-account-templates `boolean`\ When used with `external-id`, includes both templates matching the external ID **and** account templates (templates without an external ID) in the initial template selection modal. Default: `false` move-to-folder `string`\ Automatically move saved templates to this folder ID load-uploads `boolean`\ Load user uploads in the assets panel. Default: `false` external-assets-endpoint `string`\ URL of an endpoint you host that returns your own list of images and videos to preload in the Uploads panel. When set, an **External Assets** tab is added to the panel (and shown by default) where users can click any asset to add it to the template. The request is proxied server-side, so the endpoint only needs to be publicly reachable, no CORS configuration is required. See [External Assets Endpoint](#external-assets-endpoint) for the expected response format. preview-on-download `boolean`\ When enabled, JPG and PNG downloads open a modal showing the rendered image with instructions for the user to press and hold to save it to their device, instead of triggering a file download. Useful for mobile WebViews where direct downloads are blocked or unreliable. Default: `false` ## Usage Examples [Section titled “Usage Examples”](#usage-examples) ### Preview Mode with Layer Controls [Section titled “Preview Mode with Layer Controls”](#preview-mode-with-layer-controls) Preview Mode with Interactive Layers ```html ``` ### Clean Canvas without Background Pattern [Section titled “Clean Canvas without Background Pattern”](#clean-canvas-without-background-pattern) Editor with Transparent Canvas Background ```html ``` Alternative using canvas-background parameter ```html ``` ### Template Gallery with Restrictions [Section titled “Template Gallery with Restrictions”](#template-gallery-with-restrictions) Gallery Mode with Limited Permissions ```html ``` ### Folder-Specific Templates [Section titled “Folder-Specific Templates”](#folder-specific-templates) Templates from Specific Folder ```html ``` ### Custom Dimensions and Image [Section titled “Custom Dimensions and Image”](#custom-dimensions-and-image) Custom Template with Background Image ```html ``` ### Render Editing with Session [Section titled “Render Editing with Session”](#render-editing-with-session) Edit Existing Render with User Session ```html ``` ### Single Page from Multi-Page Template [Section titled “Single Page from Multi-Page Template”](#single-page-from-multi-page-template) Display Only One Page ```html ``` ### Multi-User Environment [Section titled “Multi-User Environment”](#multi-user-environment) Agency Portal with Client Sessions ```html ``` ### Combined Account and External ID Templates [Section titled “Combined Account and External ID Templates”](#combined-account-and-external-id-templates) Show Both Account Templates and User-Specific Templates ```html ``` ### Mobile-Friendly Download (Press and Hold to Save) [Section titled “Mobile-Friendly Download (Press and Hold to Save)”](#mobile-friendly-download-press-and-hold-to-save) Show Image Preview Instead of Downloading ```html ``` Use this when embedding the editor inside a mobile app’s WebView. After the user clicks Download, the rendered JPG or PNG is shown in a modal so they can press and hold the image to save it to their gallery — bypassing the native download trigger that mobile WebViews often block. ### Hiding Specific Sidebar Tabs [Section titled “Hiding Specific Sidebar Tabs”](#hiding-specific-sidebar-tabs) Editor with Hidden Barcode and Rating Tabs ```html ``` Minimal Editor with Only Text and Images Tabs ```html ``` ### Preloading Your Own Images and Videos [Section titled “Preloading Your Own Images and Videos”](#preloading-your-own-images-and-videos) Editor with a Custom Asset Library ```html ``` This loads your own images and videos into an **External Assets** tab in the Uploads panel, so users can drop your brand assets, product photos, or stock library straight into the template. See [External Assets Endpoint](#external-assets-endpoint) below for the response format your endpoint must return. ## Parameter Combinations [Section titled “Parameter Combinations”](#parameter-combinations) Common Parameter Combinations **Preview Mode for Interactive Demos:** ```plaintext ?embed=CONFIG&preview=true&allow-layer-move=true&allow-text-edition=true&zoom=50 ``` **Restricted Editor for End Users:** ```plaintext ?embed=CONFIG&clone=true&allow-download=false&allow-resize=false&hide-sidebar=true ``` **Agency Client Portal:** ```plaintext ?embed=CONFIG&folder=CLIENT_FOLDER&clone=true&allow-create-template=false&external-id=client-acme-corp ``` **Hybrid Template Access (Account + User Templates):** ```plaintext ?embed=CONFIG&launch-mode=user-templates&external-id=user-123&include-account-templates=true ``` **Educational Platform:** ```plaintext ?embed=CONFIG&launch-mode=gallery&allow-layer-unlock=true&load-uploads=true ``` **Single Page from Multi-Page Template:** ```plaintext ?embed=CONFIG&page=Cover&hide-sidebar=true&hide-header=true ``` **Text-Only Editing (Lock Non-Text Layers):** ```plaintext ?embed=CONFIG&allow-edit-text-only=true&hide-sidebar=true ``` **Simplified Sidebar (Hide Advanced Tabs):** ```plaintext ?embed=CONFIG&hide-tabs=qr-code,barcode,rating ``` **Branded Asset Library:** ```plaintext ?embed=CONFIG&external-assets-endpoint=https://yourdomain.com/api/editor-assets ``` ## External ID Sessions [Section titled “External ID Sessions”](#external-id-sessions) The `external-id` parameter creates persistent sessions for your embedded editor instances. This is particularly useful for maintaining user context and asset continuity across multiple editor sessions. ### How External ID Works [Section titled “How External ID Works”](#how-external-id-works) When you provide an `external-id`, the editor: 1. **Tags all created content** with this identifier 2. **Persists user uploads** and custom fonts for future sessions 3. **Makes tagged entities accessible** via the API using the same ID 4. **Maintains session continuity** when users return to the editor ### What Gets Tagged [Section titled “What Gets Tagged”](#what-gets-tagged) All content created during the session is tagged with the external ID: Templates\ Any templates created or saved during the session Renders\ All renders generated from templates in this session Uploads\ Images and assets uploaded by the user Fonts\ Custom fonts added during the session ### Usage Examples [Section titled “Usage Examples”](#usage-examples-1) * User Sessions User-Specific Session ```html ``` When user-123 returns to the editor, all their previous uploads and fonts will be available. * Project Sessions Project-Specific Session ```html ``` Perfect for maintaining project-specific assets and branding consistency. * Client Sessions Client-Specific Session ```html ``` Keep each client’s assets, fonts, and templates separate and organized. ### API Integration [Section titled “API Integration”](#api-integration) All entities tagged with an external ID can be retrieved via the Templated API: Fetch Templates by External ID ```js // Get all templates for a specific external ID const response = await fetch('https://api.templated.io/v1/templates?external_id=user-123', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const templates = await response.json(); ``` Fetch Uploads by External ID ```js // Get all uploads for a specific external ID const response = await fetch('https://api.templated.io/v1/uploads?external_id=project-abc-campaign', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const uploads = await response.json(); ``` ### Best Practices [Section titled “Best Practices”](#best-practices) External ID Best Practices **Naming Convention:** * Use descriptive, unique identifiers * Include context: `user-{id}`, `project-{name}`, `client-{company}` * Avoid special characters that might cause URL encoding issues **Session Management:** * Use the same external ID consistently for the same user/project/client * Consider implementing session cleanup for inactive external IDs * Document your external ID strategy for your team **API Integration:** * Use external IDs to filter API responses * Implement external ID-based data exports * Consider external IDs in your backup and archival strategies ## External Assets Endpoint [Section titled “External Assets Endpoint”](#external-assets-endpoint) The `external-assets-endpoint` parameter lets you populate the editor’s Uploads panel with your own images and videos, so end users can add brand assets, product photos, or a curated stock library to their templates without uploading anything themselves. ### How It Works [Section titled “How It Works”](#how-it-works) 1. You pass the URL of an endpoint you host via `external-assets-endpoint`. 2. Templated fetches that URL **server-side** (proxied through the backend with a 10 second timeout), so your endpoint only needs to be publicly reachable, no CORS setup is required. 3. The returned assets appear in a dedicated **External Assets** tab in the Uploads panel, which becomes the default active tab. 4. Clicking an asset adds it to the template as an image or video layer. Users can still switch to the **My Uploads** tab to access their own uploaded files. ### Response Format [Section titled “Response Format”](#response-format) Your endpoint must return a JSON **array** of asset objects. Each object requires two fields: url `string`\ The full, publicly accessible URL of the image or video. type `string`\ The asset type. Must be either `'image'` or `'video'`. Example Response ```json [ { "url": "https://cdn.example.com/logos/logo-primary.png", "type": "image" }, { "url": "https://cdn.example.com/photos/product-front.jpg", "type": "image" }, { "url": "https://cdn.example.com/videos/promo-15s.mp4", "type": "video" } ] ``` Validation Items missing a `url`, or with a `type` other than `image` or `video`, are silently ignored. If the endpoint is unreachable or does not return a JSON array, the External Assets tab shows an error and no assets are loaded. ## Data Encoding [Section titled “Data Encoding”](#data-encoding) For parameters that accept JSON data (`layers`, `metadata`), you must base64-encode the JSON string: * JavaScript Encoding Layer Data ```js const layerData = { "headline": { text: "Custom Title", color: "#FF0000" }, "description": { text: "Custom description text" } }; const encodedLayers = btoa(JSON.stringify(layerData)); const embedUrl = `https://app.templated.io/editor/TEMPLATE_ID?embed=CONFIG_ID&layers=${encodedLayers}`; ``` * Python Encoding Layer Data in Python ```python import json import base64 layer_data = { "headline": {"text": "Custom Title", "color": "#FF0000"}, "description": {"text": "Custom description text"} } encoded_layers = base64.b64encode( json.dumps(layer_data).encode('utf-8') ).decode('utf-8') embed_url = f"https://app.templated.io/editor/TEMPLATE_ID?embed=CONFIG_ID&layers={encoded_layers}" ``` Parameter Testing Use your browser’s developer tools to test parameter combinations. The editor will log parameter values to the console, helping you debug your integration. ## See Also [Section titled “See Also”](#see-also) * [Configuration](/docs/embed/configuration/) - Dashboard configuration options * [Preview Mode](/docs/embed/preview-mode/) - Canvas-only embedding * [Advanced Features](/docs/embed/advanced/) - Complex integration patterns * [Launch Modes](/docs/embed/launch-modes/) - Different ways to initialize the editor # Webhook Integration > Learn how to receive real-time notifications when users interact with your embedded editor. Webhooks allow you to receive real-time notifications when users save or download templates in your embedded editor. This enables you to track user activity, sync data, and trigger workflows in your application. ## How Webhooks Work [Section titled “How Webhooks Work”](#how-webhooks-work) When a user performs an action in the embedded editor, Templated sends a POST request to your webhook URL with details about the action. 1. **User performs action** (create, save or download) in the embedded editor 2. **Templated processes the action** and captures relevant data 3. **HTTP POST request sent** to your configured webhook URL 4. **Your server receives** and processes the webhook data 5. **Your application responds** with appropriate actions or data storage ## Webhook Configuration [Section titled “Webhook Configuration”](#webhook-configuration) Set up your webhook URL in the embed configuration: 1. Go to your **Embed Setup** page 2. Expand **Advanced Settings** 3. Enter your webhook URL in the **Webhook URL** field 4. Save your configuration ## Webhook Events [Section titled “Webhook Events”](#webhook-events) Webhooks are triggered for the following actions: ### Create Event [Section titled “Create Event”](#create-event) Triggered when a user creates a new template in the embedded editor. Create Event Payload ```json { "action": "create", "templateId": "tpl_456def", "metadata": { // Custom metadata passed from your application } } ``` ### Save Event [Section titled “Save Event”](#save-event) Triggered when a user saves a template in the embedded editor. Save Event Payload ```json { "action": "save", "templateId": "tpl_456def", "metadata": { // Custom metadata passed from your application } } ``` ### Download Event [Section titled “Download Event”](#download-event) Triggered when a user downloads a template from the embedded editor. Download Event Payload ```json { "action": "download", "templateId": "tpl_456def", "metadata": { // Custom metadata passed from your application } } ``` ## Frontend Event Listening [Section titled “Frontend Event Listening”](#frontend-event-listening) You can also listen for events directly in the frontend using the `postMessage` API. This is useful for immediate UI updates or client-side tracking. Frontend Event Listener ```js window.addEventListener('message', (event) => { // Verify origin for security if (event.origin !== 'https://app.templated.io') { return; } const { action, templateId, metadata } = event.data; switch (action) { case 'create': console.log('Template created:', templateId); console.log('Metadata:', metadata); // Update UI, show success message, etc. break; case 'save': console.log('Template saved:', templateId); console.log('Metadata:', metadata); // Track analytics, update download count, etc. break; case 'download': console.log('Template downloaded:', templateId); console.log('Metadata:', metadata); // Handle cleanup, redirect, etc. break; } }); ``` Frontend vs Backend Events **Frontend Events:** Immediate UI updates, client-side tracking, user feedback\ **Backend Webhooks:** Data persistence, server-side processing, integrations with other systems Use both for a complete integration experience. ## How to implement a basic webhook handler in your application? [Section titled “How to implement a basic webhook handler in your application?”](#how-to-implement-a-basic-webhook-handler-in-your-application) * Node.js/Express Express Webhook Handler ```js const express = require('express'); const app = express(); // Middleware to parse JSON app.use(express.json()); app.post('/api/templated-webhook', (req, res) => { const { action, templateId, metadata } = req.body; console.log(`Received ${action} action for template ${templateId}`); switch (action) { case 'create': handleCreateEvent(templateId, metadata); break; case 'save': handleSaveEvent(templateId, metadata); break; case 'download': handleDownloadEvent(templateId, metadata); break; default: console.log('Unknown action type:', action); } // Respond with 200 to acknowledge receipt res.status(200).json({ received: true }); }); function handleCreateEvent(templateId, metadata) { // Your create logic here console.log(`Template ${templateId} created`); if (metadata && Object.keys(metadata).length > 0) { console.log('Metadata:', metadata); } } function handleSaveEvent(templateId, metadata) { // Update user's project with new template // Log activity // Send notifications console.log(`Template ${templateId} saved`); if (metadata && Object.keys(metadata).length > 0) { console.log('Metadata:', metadata); } } function handleDownloadEvent(templateId, metadata) { // Track download metrics // Update user quotas // Trigger follow-up workflows console.log(`Template ${templateId} downloaded`); if (metadata && Object.keys(metadata).length > 0) { console.log('Metadata:', metadata); } } ``` * Python/Flask Flask Webhook Handler ```python from flask import Flask, request, jsonify import json from datetime import datetime app = Flask(__name__) @app.route('/api/templated-webhook', methods=['POST']) def handle_webhook(): data = request.get_json() action = data.get('action') template_id = data.get('templateId') metadata = data.get('metadata', {}) print(f"Received {action} action for template {template_id}") if action == 'create': handle_create_event(template_id, metadata) elif action == 'save': handle_save_event(template_id, metadata) elif action == 'download': handle_download_event(template_id, metadata) else: print(f"Unknown action type: {action}") return jsonify({'received': True}), 200 def handle_create_event(template_id, metadata): # Your create logic here print(f"Template {template_id} created") if metadata: print(f"Metadata: {metadata}") def handle_save_event(template_id, metadata): # Your save logic here print(f"Template {template_id} saved") if metadata: print(f"Metadata: {metadata}") def handle_download_event(template_id, metadata): # Your download logic here print(f"Template {template_id} downloaded") if metadata: print(f"Metadata: {metadata}") if __name__ == '__main__': app.run(debug=True) ``` * PHP PHP Webhook Handler ```php 'Invalid JSON']); exit; } $action = $data['action'] ?? ''; $templateId = $data['templateId'] ?? ''; $metadata = $data['metadata'] ?? []; error_log("Received {$action} action for template {$templateId}"); switch ($action) { case 'create': handleCreateEvent($templateId, $metadata); break; case 'save': handleSaveEvent($templateId, $metadata); break; case 'download': handleDownloadEvent($templateId, $metadata); break; default: error_log("Unknown action type: {$action}"); } // Respond with success http_response_code(200); echo json_encode(['received' => true]); function handleCreateEvent($templateId, $metadata) { // Your create logic here error_log("Template {$templateId} created"); if (!empty($metadata)) { error_log("Metadata: " . json_encode($metadata)); } } function handleSaveEvent($templateId, $metadata) { // Your save logic here error_log("Template {$templateId} saved"); if (!empty($metadata)) { error_log("Metadata: " . json_encode($metadata)); } } function handleDownloadEvent($templateId, $metadata) { // Your download logic here error_log("Template {$templateId} downloaded"); if (!empty($metadata)) { error_log("Metadata: " . json_encode($metadata)); } } ?> ``` ## Troubleshooting common issues [Section titled “Troubleshooting common issues”](#troubleshooting-common-issues) Webhook not receiving data → Verify your webhook URL is publicly accessible\ → Check that your server responds with 200 status code\ → If you’re passing metadata, ensure you’re parsing JSON correctly Missing metadata → Verify metadata is being passed in the embed URL in the correct format\ → Check that metadata is properly base64 encoded Timeout errors → Ensure your webhook handler responds quickly (< 10 seconds)\ → Consider processing heavy operations asynchronously # Create a folder > Learn how to create a new folder using the Templated API. Create a new folder to organize your templates. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to create a new folder: ENDPOINT ```js POST /v1/folder ``` REQUEST ```js fetch('https://api.templated.io/v1/folder', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': Bearer ${API_KEY} }, body: JSON.stringify({ name: "My New Folder" }) }) ``` ### Request Body [Section titled “Request Body”](#request-body) name `string` `REQUIRED`\ The name of the folder you want to create. ## Response [Section titled “Response”](#response) The API returns a JSON object with the folder details. ```json { "id": "fld_123abc", "name": "My New Folder", "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:30:00Z" } ``` # Delete a folder > Learn how to delete a folder using the Templated API. Delete an existing folder and remove folder references from all templates within it.\ Templates themselves are not deleted, only their association with the folder. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to delete a folder: ENDPOINT ```js DELETE /v1/folder/{id} ``` REQUEST ```js fetch(`https://api.templated.io/v1/folder/${folderId}`, { method: 'DELETE', headers: { 'Authorization': Bearer ${API_KEY} } }) ``` ### Path Parameters [Section titled “Path Parameters”](#path-parameters) id `string` `REQUIRED`\ The unique identifier of the folder you want to delete. ## Response [Section titled “Response”](#response) A successful deletion returns an empty response with a 204 status code. When deleting a folder: * All templates previously in the folder will have their folder reference removed * The folder will be permanently deleted * Templates themselves are not deleted, only their association with the folder # The folder object > Learn the properties of a folder object in the Templated API. These attributes define the properties of a folder.\ The folder object is used to store templates and renders in an organized way. ## Attributes [Section titled “Attributes”](#attributes) id `string`\ The unique UUID for the folder. name `string`\ The name of the folder. createdAt `string`\ The timestamp when the folder was created. updatedAt `string`\ The timestamp when the folder was last updated. ## Sample Object [Section titled “Sample Object”](#sample-object) Here’s a sample object of a folder: ```json { "id": "3c435c83-6682-4468-939f-6af175caacex", "name": "Marketing Folder", "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:30:00Z" } ``` # List all folders > Learn the list all folders of an user using the Templated API. Lists all folders of an user.\ You can filter and customize the results using query parameters. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------- | ------- | ------- | -------------------------- | | `query` | string | - | Filter folders by name | | `page` | integer | 0 | Page number for pagination | | `limit` | integer | 25 | Number of results per page | ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all user’s folders: ENDPOINT ```js GET /v1/folders ``` * JavaScript ```js fetch(`https://api.templated.io/v1/folders`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` }, // Example with all query parameters params: { query: 'Folder 1', page: 0, limit: 25 } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' url = 'https://api.templated.io/v1/folders' # Example with all query parameters params = { 'query': 'My Folder', 'page': 0, 'limit': 25 } headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, params=params, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; public class ListFolders { public static void main(String[] args) { try { String apiKey = "API_KEY"; // Example with all query parameters String queryParams = String.format("?query=%s&page=%d&limit=%d", URLEncoder.encode("My Folder", "UTF-8"), 0, 25 ); URL url = new URL("https://api.templated.io/v1/folders" + queryParams); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php 'My Folder', 'page' => 0, 'limit' => 25 ); $url = "https://api.templated.io/v1/folders?" . http_build_query($params); $options = ``` ## Response [Section titled “Response”](#response) The API returns an array of JSON objects with the folder details. ```json [ { "id": "fld_123abc", "name": "My Templates", "templateCount": 12, "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:30:00Z" }, { "id": "fld_456def", "name": "Brand Assets", "templateCount": 5, "createdAt": "2024-03-19T15:45:00Z", "updatedAt": "2024-03-20T09:15:00Z" } ] ``` Each folder object contains the following properties: id `string`\ The unique identifier of the folder. name `string`\ The name of the folder. templateCount `integer`\ The number of templates in the folder. createdAt `string`\ The timestamp when the folder was created. updatedAt `string`\ The timestamp when the folder was last updated. # Move render to folder > Learn how to move a render to a folder using the Templated API. Move an existing render into a folder. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to move a render to a folder: ENDPOINT ```js PUT /v1/folder/{folderId}/render/{renderId} ``` REQUEST ```js fetch(`https://api.templated.io/v1/folder/${folderId}/render/${renderId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Path Parameters [Section titled “Path Parameters”](#path-parameters) folderId `string` `REQUIRED`\ The ID of the folder where you want to move the render. renderId `string` `REQUIRED`\ The ID of the render you want to move. ## Response [Section titled “Response”](#response) A successful request returns an empty response with a `200 OK` status code. # List folder renders > Learn how to list all renders of a folder using the Templated API. Lists all renders of a folder. ## Parameters [Section titled “Parameters”](#parameters) folderId `string` `REQUIRED`\ The folder ID that you want to retrieve the renders from. page `number`\ The page number for pagination. Defaults to 0. limit `number`\ The number of renders per page. Defaults to 25. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all renders of a folder: ENDPOINT ```js GET /v1/folder/:folderId/renders ``` REQUEST ```js fetch(`https://api.templated.io/v1/folder/${folderId}/renders?page=0&limit=25`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns an array of JSON objects with the render details. ```json [ { "id": "rnd_123abc", "url": "renders/2024/03/my-render.png", "status": "completed", "width": 1080, "height": 1080, "folderId": "fld_456def", "templateId": "tpl_789ghi", "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:30:00Z" } ] ``` # Move template to folder > Learn how to move a template to a folder using the Templated API. Move an existing template into a folder. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to move a template to a folder: ENDPOINT ```js PUT /v1/folder/{folderId}/template/{templateId} ``` REQUEST ```js fetch(`https://api.templated.io/v1/folder/${folderId}/template/${templateId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Path Parameters [Section titled “Path Parameters”](#path-parameters) folderId `string` `REQUIRED`\ The ID of the folder where you want to move the template. templateId `string` `REQUIRED`\ The ID of the template you want to move. ## Response [Section titled “Response”](#response) A successful request returns an empty response with a `200 OK` status code. # List folder templates > Learn the list all templates of a folder using the Templated API. Lists all templates of a folder.\ You can filter and customize the results using various query parameters. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED` The folder id that you want to retrieve the templates. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------------- | ------- | ------- | ----------------------------------- | | `query` | string | - | Filter templates by name | | `page` | integer | 0 | Page number for pagination | | `limit` | integer | 25 | Number of results per page | | `width` | integer | - | Filter templates by width | | `height` | integer | - | Filter templates by height | | `tags` | string | - | Filter templates by tags | | `includeLayers` | boolean | false | Include template layers in response | ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all templates of a folder: ENDPOINT ```js GET /v1/folder/:id/templates ``` * JavaScript ```js fetch(`https://api.templated.io/v1/folder/${id}/templates`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` }, // Example with all query parameters params: { query: 'Template Name', page: 0, limit: 25, width: 1920, height: 1080, tags: 'tag1,tag2', includeLayers: true } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' folder_id = 'id' url = f'https://api.templated.io/v1/folder/{folder_id}/templates' # Example with all query parameters params = { 'query': 'Template Name', 'page': 0, 'limit': 25, 'width': 1920, 'height': 1080, 'includeLayers': True } headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, params=params, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; public class ListFolderTemplates { public static void main(String[] args) { try { String apiKey = "API_KEY"; String folderId = "id"; // Example with all query parameters String queryParams = String.format("?query=%s&page=%d&limit=%d&width=%d&height=%d&includeLayers=%b", URLEncoder.encode("Template Name", "UTF-8"), 0, 25, 1920, 1080, true ); URL url = new URL("https://api.templated.io/v1/folder/" + folderId + "/templates" + queryParams); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php 'Template Name', 'page' => 0, 'limit' => 25, 'width' => 1920, 'height' => 1080, 'includeLayers' => 'true' ); $url = "https://api.templated.io/v1/folder/{$folderId}/templates?" . http_build_query($params); $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` ## Response [Section titled “Response”](#response) The API returns an array of JSON objects with the template details. ```json [ { "id": "tpl_123abc", "name": "Instagram Post", "width": 1080, "height": 1080, "thumbnail": "https://templated-assets.s3.amazonaws.com/thumbnail-123.png", "folderId": "fld_456def", "layersCount": 5, "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:30:00Z", } ] ``` # Update a folder > Learn how to update a folder using the Templated API. Update a folder to change its name. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to update a folder: ENDPOINT ```js PUT /v1/folder/{id} ``` REQUEST ```js fetch(`https://api.templated.io/v1/folder/${folderId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ name: "My Updated Folder" }) }) ``` ### Request Body [Section titled “Request Body”](#request-body) name `string` `REQUIRED`\ The new name for the folder. ## Response [Section titled “Response”](#response) The API returns a JSON object with the updated folder details. ```json { "id": "fld_123abc", "name": "My Updated Folder", "createdAt": "2024-03-20T10:30:00Z", "updatedAt": "2024-03-20T10:35:00Z" } ``` # Delete fonts > Learn how to delete one or multiple fonts by name using the Templated API. Delete one or multiple fonts by their names. All fonts with the specified names will be deleted for your account. If you have multiple fonts with the same name, all of them will be deleted. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to delete fonts: ENDPOINT ```js DELETE /v1/fonts?fonts=FONT_NAME_1&fonts=FONT_NAME_2 ``` * JavaScript ```js // Delete single font fetch(`https://api.templated.io/v1/fonts?fonts=${encodeURIComponent('My Custom Font')}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log('Response:', data)) .catch(error => console.error('Error:', error)); // Delete multiple fonts const fontNames = ['My Custom Font', 'Another Font']; const params = fontNames.map(name => `fonts=${encodeURIComponent(name)}`).join('&'); fetch(`https://api.templated.io/v1/fonts?${params}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log('Response:', data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' font_names = ['My Custom Font', 'Another Font'] # Prepare query parameters params = {'fonts': font_names} url = 'https://api.templated.io/v1/fonts' headers = {'Authorization': f'Bearer {api_key}'} response = requests.delete(url, headers=headers, params=params) if response.status_code == 200: result = response.json() print(f"Successfully deleted: {result['deleted']}") print(f"Deleted by name: {result['deleted_by_name']}") print(result['message']) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.io.BufferedReader; import java.io.InputStreamReader; public class DeleteFonts { public static void main(String[] args) { try { String apiKey = "API_KEY"; String[] fontNames = {"My Custom Font", "Another Font"}; // Build query parameters StringBuilder params = new StringBuilder(); for (int i = 0; i < fontNames.length; i++) { if (i > 0) params.append("&"); params.append("fonts=").append(URLEncoder.encode(fontNames[i], "UTF-8")); } URL url = new URL("https://api.templated.io/v1/fonts?" + params.toString()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("DELETE"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String response = reader.readLine(); System.out.println("Response: " + response); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php $fontNames]); $url = "https://api.templated.io/v1/fonts?{$params}"; $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result !== false) { $response = json_decode($result, true); echo "Successfully deleted: " . implode(', ', $response['deleted']) . "\n"; echo "Deleted by name: " . json_encode($response['deleted_by_name']) . "\n"; echo $response['message'] . "\n"; } else { echo "Error deleting fonts\n"; } ?> ``` ## Response [Section titled “Response”](#response) ### Success Response [Section titled “Success Response”](#success-response) A successful deletion will return a `200 OK` response with details about the deleted fonts: ```json { "deleted": ["font-id-1", "font-id-2", "font-id-3"], "deleted_by_name": { "My Custom Font": 2, "Another Font": 1 }, "message": "Successfully deleted 3 font(s)" } ``` The `deleted_by_name` object shows how many fonts were deleted for each font name. This is useful when you have multiple fonts with the same name. ### Error Responses [Section titled “Error Responses”](#error-responses) | Status Code | Description | Response Body | | ----------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | 400 | Bad Request - Font name(s) not found | `{"not_found": ["Font Name"], "error": "Cannot delete fonts: no fonts found with the specified name(s) for this user"}` | | 400 | Bad Request - No font names provided | `{"error": "At least one font name must be provided"}` | | 401 | Not authorized - Invalid or missing API key | `{"error": "Not authorized"}` | | 404 | Not Found - User not found | `{"error": "User not found"}` | | 500 | Internal Server Error - An unexpected error occurred | `{"error": "An unexpected error occurred"}` | ## Important Notes [Section titled “Important Notes”](#important-notes) * **Atomic Operation**: Either all fonts with the specified names are deleted, or none are deleted. If any font name has no matching fonts, the entire operation fails. * **Bulk Support**: You can delete fonts with multiple names in a single request by passing multiple `fonts` parameters. * **Multiple Fonts**: If you have multiple fonts with the same name, all of them will be deleted when that name is specified. * **Name Matching**: Font names must match exactly (case-sensitive). ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Required | Description | | --------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `fonts` | string\[] | Yes | One or more font names to delete. Pass multiple `fonts` parameters for bulk deletion. All fonts with matching names will be deleted. | # List gallery fonts > Retrieve all base fonts available in the Templated editor using the API. Lists all base fonts available in the Templated editor.\ Unlike `/v1/fonts`, this endpoint does not include team-uploaded fonts — it only returns the fonts built into the editor. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------- | ------- | ------- | --------------------------------------- | | `query` | string | - | Filter fonts by name (case-insensitive) | | `page` | integer | 0 | Page number for pagination | | `limit` | integer | 50 | Number of results per page | ## Response [Section titled “Response”](#response) Returns an array of font objects. Each object includes the following field: | Field | Type | Description | | ------ | ------ | --------------------------------------------------------- | | `name` | string | The font name (use directly as a CSS `font-family` value) | ## Sample Request [Section titled “Sample Request”](#sample-request) ENDPOINT ```js GET /v1/fonts/gallery ``` * JavaScript ```js fetch('https://api.templated.io/v1/fonts/gallery', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' url = 'https://api.templated.io/v1/fonts/gallery' headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` ## Sample Response [Section titled “Sample Response”](#sample-response) ```json [ { "name": "ABeeZee" }, { "name": "Abel" }, { "name": "Bai Jamjuree" }, { "name": "Dancing Script" }, { "name": "IBM Plex Sans" }, { "name": "JetBrains Mono" }, { "name": "Poppins" }, { "name": "proxima-nova" }, { "name": "Raleway" }, { "name": "Ubuntu" } ] ``` ## Filtering Examples [Section titled “Filtering Examples”](#filtering-examples) ### Search by Name [Section titled “Search by Name”](#search-by-name) ```js fetch('https://api.templated.io/v1/fonts/gallery?query=noto', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ## Available Fonts [Section titled “Available Fonts”](#available-fonts) Below is the complete list of fonts available in the gallery. | Font | Font | Font | | ------------------------ | ----------------------- | --------------------- | | ABeeZee | IM Fell DW Pica | Quando | | Abel | Jacques Francois | Quantico | | Abhaya Libre | Jacques Francois Shadow | Quattrocento | | Abril Fatface | Jaldi | Quattrocento Sans | | Aclonica | JetBrains Mono | Questrial | | Agenda-Bold | Jim Nightshade | Racing Sans One | | Bad Script | K2D | Radley | | Bahiana | Kadwa | Rajdhani | | Bahianita | Kalam | Rakkas | | Bai Jamjuree | Kameron | Raleway | | Baloo 2 | Kanit | Sacramento | | Cabin | Lacquer | Sahitya | | Cabin Condensed | Laila | Sail | | Cabin Sketch | Lakki Reddy | Saira | | Caesar Dressing | Lalezar | Saira Condensed | | Cagliostro | Lancelot | Tajawal | | Co Headline Corp Regular | Lexend | Tangerine | | Damion | M PLUS 1p | Taprom | | Dancing Script | M PLUS Rounded 1c | Tauri | | Dangrek | Ma Shan Zheng | Taviraj | | Darker Grotesque | Macondo | Ubuntu | | David Libre | Macondo Swash Caps | Ubuntu Condensed | | Eagle Lake | Nanum Brush Script | Ubuntu Mono | | East Sea Dokdo | Nanum Gothic | Ultra | | Economica | Nanum Gothic Coding | Uncial Antiqua | | Eczar | Nanum Myeongjo | Vampiro One | | El Messiri | Nanum Pen Script | Varela | | Fanwood Text | Noto Color Emoji | Varela Round | | Farro | Noto Sans | Varta | | Fascinate | Noto Sans Arabic | Vast Shadow | | Fascinate Inline | Noto Sans Bengali | Walter Turncoat | | Faster One | Noto Sans Gurmukhi | Warnes | | Gabriela | Noto Sans JP | Wellfleet | | Gaegu | Noto Sans KR | Wendy One | | Gafata | Noto Sans Thai | Wire One | | Geist | Odibee Sans | Xanh Mono | | GFS Didot | Odor Mean Chey | Yanone Kaffeesatz | | GFS Neohellenic | Offside | Yantramanav | | Habibi | Old Standard TT | Yatra One | | Hachi Maru Pop | Oldenburg | Yellowtail | | Halant | Padauk | Yeon Sung | | Hammersmith One | Palanquin | ZCOOL KuaiLe | | IBM Plex Mono | Palanquin Dark | ZCOOL QingKe HuangYou | | IBM Plex Sans | Pangolin | ZCOOL XiaoWei | | IBM Plex Sans Arabic | Paprika | Zeyada | | IBM Plex Sans Condensed | Poppins | Zilla Slab | | IBM Plex Serif | proxima-nova | | # The font object > Learn the properties of a font object in the Templated API. These attributes define the properties of a font object.\ The font object represents both Google Fonts and user-uploaded custom fonts. ## Attributes [Section titled “Attributes”](#attributes) name `string`\ The name of the font. isGoogleFont `boolean`\ Indicates if the font is from Google Fonts. isUploadedFont `boolean`\ Indicates if the font is a user-uploaded custom font. ## Sample Objects [Section titled “Sample Objects”](#sample-objects) Here’s a sample object of a Google Font: ```json { "name": "Roboto", "isGoogleFont": true, "isUploadedFont": false, } ``` # List all fonts > Learn how to retrieve both Google Fonts and user-uploaded fonts using the Templated API. Lists all available fonts, including both Google Fonts and user-uploaded custom fonts. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all available fonts: ENDPOINT ```js GET /v1/fonts ``` REQUEST ```js fetch('https://api.templated.io/v1/fonts', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The response will be an array of font objects. Each object will follow either the Google Font or user-uploaded font structure. ```json [ { "name": "Roboto", "isGoogleFont": true, "isUploadedFont": false, }, { "name": "My Custom Font", "isGoogleFont": false, "isUploadedFont": true, } // ... more fonts ] ``` # Upload a font > Learn to upload custom fonts using the Templated API. Upload a custom font to your account for use in your templates. ## Requirements [Section titled “Requirements”](#requirements) * Font file must be in TTF, OTF, WOFF, or WOFF2 format * Maximum file size: 10MB * You must be on a paid plan to upload custom fonts Note Custom font uploads are only available for paid plans. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to upload a font: ENDPOINT ```js POST /v1/font Content-Type: multipart/form-data ``` ```js // Create form data const fileInput = document.getElementById('fontFileInput'); const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('https://api.templated.io/v1/font', { method: 'POST', body: formData, headers: { 'Authorization' : `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error uploading font:', error)); ``` # Templated API Documentation > The documentation of the Templated API for automating the generation of images, videos, and PDFs. With the Templated API you can automate the generation of images, videos, and PDFs.\ This guide will help you get started integrating with our simple API. ## Getting Started [Section titled “Getting Started”](#getting-started) 1. [Sign up](https://app.templated.io/signup) for an account. 2. Create your template in our editor, import from Canva or select one from our Template Gallery. [Templated Editor Demo Video](https://www.youtube.com/embed/WXH5XcbSLuA?si=zC7hB9aCxBPYXf89&\&controls=1\&autoplay=1\&loop=1\&rel=0) 3. Get your API key in your dashboard in the [API Key](https://app.templated.io/api-key) tab. 4. Make a call to generate a render (image, video, or PDF). SAMPLE REQUEST ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify({ template: TEMPLATE_ID, layers: { 'text-1': { text: 'This is my text to be rendered', color: '#FF0000', background: '#0000FF', }, 'image-1': { image_url: 'https://picsum.photos/200/300.jpg', }, }, }), headers: { 'Content-Type': 'application/json', 'Authorization' : `Bearer ${API_KEY}` }, }); ``` 5. Integrate our API to your workflow.\ Check the [Create a render](/docs/renders/create/) endpoint documentation for more details. ### Try it in Postman [Section titled “Try it in Postman”](#try-it-in-postman) Want to explore our API quickly? Check out our complete API collection in Postman where you can test all endpoints, see request examples, and get started faster. [![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/50230789-960e9f9f-e7b1-4097-ad87-cf35f9e746cc) # Custom Storage (Bring Your Own Storage) > Deliver every render straight to your own AWS S3 or Cloudflare R2 bucket. Store your renders in your own bucket. When custom storage is connected, every completed render is delivered to your AWS S3, Cloudflare R2, or any S3-compatible bucket, and the API response and webhooks include the URL of your copy in a `storage_url` field. **Availability:** Scale and Enterprise plans. Configured by a team owner or admin in [Account Settings](https://app.templated.io/account). ## Storage modes [Section titled “Storage modes”](#storage-modes) | Mode | What happens | | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Keep a copy on Templated** (default) | Your bucket receives a copy of every render; Templated keeps its own copy too. Dashboard previews, merges and zips keep working exactly as before. | | **Store only in my bucket** | Your bucket is the only durable home of the render. Templated’s transient copy is deleted right after your copy is confirmed. The `url` field of the render points to your bucket. | Caution With **Store only in my bucket**, dashboard previews and PDF merge/zip read the render from your bucket’s URL. Make it publicly readable (set a **Public Base URL** backed by a CDN or a public bucket policy), or previews will not load. If a delivery to your bucket ever fails, Templated keeps its copy for that render, so a render never breaks. This also applies to the render download endpoint (`GET /v1/render/{id}`), which streams the file server-side, and to ZIP bundles, which skip files they cannot download. If a delivery to your bucket fails, Templated keeps its copy for that render, so only successfully delivered renders are affected. ## Setup [Section titled “Setup”](#setup) 1. In [Account Settings](https://app.templated.io/account), open **Custom Storage** → **Connect**. 2. Pick your provider: **AWS S3**, **Cloudflare R2**, or any S3-compatible service (MinIO, DigitalOcean Spaces…). 3. Fill in the credentials (see provider examples below), bucket name, and an optional folder path (defaults to `renders`). 4. Optionally set a **Public Base URL** (the public host where your objects are reachable, CDN or public bucket). It is used to build the `storage_url` returned by the API. 5. Choose the storage mode and hit **Connect**. The connection is tested automatically; you can re-run it anytime with **Test Connection**. Objects are written as `{folder}/{render_id}.{format}` (or `{folder}/{render_id}/{name}.{format}` for named renders). Templated never reads or lists objects in your bucket, and never deletes your renders. The only delete Templated ever performs is removing its own connection-test probe object. ## Minimal IAM policy (AWS S3) [Section titled “Minimal IAM policy (AWS S3)”](#minimal-iam-policy-aws-s3) Templated only needs to write objects, plus delete for the connection-test probe object: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::YOUR_BUCKET/renders/*" } ] } ``` No `GetObject`, no `ListBucket`, no ACL permissions: objects are written **without** an ACL header, so buckets with the modern Object Ownership default work as-is. ## Cloudflare R2 [Section titled “Cloudflare R2”](#cloudflare-r2) 1. Create an R2 API token with **Object Read & Write** scoped to your bucket. 2. Use the S3 endpoint `https://.r2.cloudflarestorage.com`, region `auto`. 3. R2 buckets have no public URL by default. Connect a [custom domain](https://developers.cloudflare.com/r2/buckets/public-buckets/) to the bucket and set it as the **Public Base URL**. ## API response [Section titled “API response”](#api-response) When custom storage is connected, render responses and webhooks include your copy: ```json { "id": "9f24ff01-a03e-42f5-88ba-7dbec2771231", "status": "COMPLETED", "url": "https://cdn.templated.media/render/9f24ff01.png", "storage_url": "https://assets.yourcompany.com/renders/9f24ff01.png" } ``` * `storage_url`: the confirmed URL of the copy in your bucket. `null` when custom storage is not connected or the delivery failed (Templated’s copy always survives a failed delivery). * With **Store only in my bucket**, `url` also points to your bucket after delivery. # MCP Examples > Real-world examples and use cases for the Templated MCP integration. This page provides practical examples of how to use the Templated MCP server with your AI assistant. ## Basic Examples [Section titled “Basic Examples”](#basic-examples) ### List Your Templates [Section titled “List Your Templates”](#list-your-templates) Start by exploring what templates you have available: Prompt: “Show me all my Templated templates” The AI will call `list_templates` and display your templates with their IDs, names, and dimensions. ### Create a Simple Render [Section titled “Create a Simple Render”](#create-a-simple-render) Generate an image from an existing template: Prompt: “Create a render from template \[ID] with the title set to ‘Welcome to Our Store’” Replace `[ID]` with your actual template ID. ### View Template Layers [Section titled “View Template Layers”](#view-template-layers) Before customizing a template, see what layers are available: Prompt: “What layers does template \[ID] have?” ## Customization Examples [Section titled “Customization Examples”](#customization-examples) ### Change Multiple Layers [Section titled “Change Multiple Layers”](#change-multiple-layers) Customize several layers in a single render: Prompt: “Create a render from template \[ID] with these changes: * Set the ‘headline’ layer text to ‘Summer Sale - 50% Off’ * Change the ‘headline’ color to red * Set the ‘product-image’ layer to this image: product.jpg * Change the background to #f5f5f5” ### Create Transparent PNG [Section titled “Create Transparent PNG”](#create-transparent-png) Generate an image with a transparent background: Prompt: “Generate a transparent PNG from my logo template” ### Generate a PDF [Section titled “Generate a PDF”](#generate-a-pdf) Create a PDF document: Prompt: “Create a PDF from template \[ID] with the name ‘Invoice-001’ and set the customer name to ‘John Smith‘“ ## Template Creation Examples [Section titled “Template Creation Examples”](#template-creation-examples) ### Create a Simple Template [Section titled “Create a Simple Template”](#create-a-simple-template) Build a new template from scratch: Prompt: “Create a new template called ‘Instagram Post’ with dimensions 1080x1080, a white background, and a centered text layer for the headline” ### Create a Multi-Layer Template [Section titled “Create a Multi-Layer Template”](#create-a-multi-layer-template) Build a more complex template: Prompt: “Create a template for a product announcement with: * Size: 1200x630 (Facebook post) * Gradient background from blue to purple * A large image layer on the left for the product * A headline text layer on the right in white, bold * A smaller description text layer below the headline * A ‘Buy Now’ button shape at the bottom right” ### Clone and Modify [Section titled “Clone and Modify”](#clone-and-modify) Create variations of existing templates: Prompt: “Clone my Instagram template, rename it to ‘Twitter Post’, and change the dimensions to 1200x675” ## Batch Operations [Section titled “Batch Operations”](#batch-operations) ### Multiple Renders [Section titled “Multiple Renders”](#multiple-renders) Generate several variations: Prompt: “Create 3 renders from template \[ID]: 1. Title: ‘Spring Collection’ with green background 2. Title: ‘Summer Vibes’ with yellow background 3. Title: ‘Fall Fashion’ with orange background” ### Merge into PDF [Section titled “Merge into PDF”](#merge-into-pdf) Combine multiple renders: Prompt: “Merge my last 5 renders into a single PDF called ‘Product Catalog‘“ ## Asset Management [Section titled “Asset Management”](#asset-management) ### Upload an Image [Section titled “Upload an Image”](#upload-an-image) Add an image to your library: Prompt: “Upload this image to Templated: logo.png” ### Organize with Folders [Section titled “Organize with Folders”](#organize-with-folders) Create organization structure: Prompt: “Create a folder called ‘Q1 Marketing’ and move my Instagram and Facebook templates into it” ### Upload Custom Font [Section titled “Upload Custom Font”](#upload-custom-font) Add a custom font: Prompt: “Upload this font file: ” ## Video Rendering [Section titled “Video Rendering”](#video-rendering) ### Create a Video [Section titled “Create a Video”](#create-a-video) Generate an MP4 video: Prompt: “Create a 10-second video from my animated template at 30fps” Note Video rendering uses more credits based on duration, dimensions, and FPS. See the [Create a render](/docs/renders/create/#video-credits-cost) documentation for the credit formula. ## Account Information [Section titled “Account Information”](#account-information) ### Check Usage [Section titled “Check Usage”](#check-usage) Monitor your API usage: Prompt: “Show my Templated account info and how many credits I have left” ## Real-World Workflows [Section titled “Real-World Workflows”](#real-world-workflows) ### Social Media Manager [Section titled “Social Media Manager”](#social-media-manager) Use Case: Daily Social Posts Every morning, create social media content for the day: 1. “Show me my social media templates” 2. “Create a render from my Instagram template with today’s quote: ‘Success is not final, failure is not fatal’” 3. “Clone that render but change the dimensions for Twitter (1200x675)” 4. “Create another version for Facebook stories (1080x1920)“ ### E-commerce Product Images [Section titled “E-commerce Product Images”](#e-commerce-product-images) Use Case: Product Launch Prepare marketing images for a new product: 1. “Create a folder called ‘New Product Launch’” 2. “Upload the product image: https\://…” 3. “Create a render from my product template with the image I just uploaded and title ‘New Arrival’” 4. “Make 3 more versions with different background colors: blue, green, and orange” 5. “Merge all renders into a PDF for the marketing team” ### Certificate Generation [Section titled “Certificate Generation”](#certificate-generation) Use Case: Course Completion Generate certificates for course graduates: 1. “Show me the layers in my certificate template” 2. “Create a PDF from my certificate template with: * Name: ‘Sarah Johnson’ * Course: ‘Advanced Marketing’ * Date: ‘January 28, 2026’ * Certificate ID: ‘CERT-2026-001‘“ ## Tips for Better Results [Section titled “Tips for Better Results”](#tips-for-better-results) Be Specific Include exact values for colors (hex codes), dimensions (pixels), and text content. Reference Layers by Name Use `get_template_layers` first to see layer names, then reference them accurately. Chain Operations You can ask for multiple operations in one prompt—the AI will execute them in sequence. Use Template IDs Keep your template IDs handy. The AI can look them up, but providing them is faster. # MCP Integration > Use Templated directly from AI assistants like Claude, Cursor, and ChatGPT using the Model Context Protocol. What is MCP? The Model Context Protocol (MCP) is an open standard that allows AI assistants to securely connect to external tools and data sources. With our MCP server, you can use Templated directly from Claude, Cursor, ChatGPT, and other compatible AI assistants. ## Overview [Section titled “Overview”](#overview) The Templated MCP server enables you to: * **Generate images, videos, and PDFs** using natural language commands * **Create and edit templates** directly from your AI assistant * **Manage your assets** including uploads, fonts, and folders * **Access all API features** through conversational prompts Instead of writing code or using the dashboard, simply tell your AI assistant what you want: “Create a render from my Instagram template with the title set to ‘Summer Sale’ and change the background to blue” ## Build Apps with AI Coding Tools [Section titled “Build Apps with AI Coding Tools”](#build-apps-with-ai-coding-tools) The Templated MCP works with AI-powered app builders and coding assistants. Simply prompt these tools to use Templated for image generation, and they’ll integrate it into your app automatically. [![Lovable](https://lovable.dev/favicon.ico)Lovable](https://lovable.dev)[![Replit](https://upload.wikimedia.org/wikipedia/commons/thumb/7/78/New_Replit_Logo.svg/200px-New_Replit_Logo.svg.png)Replit](https://replit.com)[![v0](https://raw.githubusercontent.com/lobehub/lobe-icons/refs/heads/master/packages/static-png/light/v0.png)v0 by Vercel](https://v0.dev)[![Base44](https://base44.com/favicon.ico)Base44](https://base44.com) **Example prompt for AI app builders:** “Build me a social media post generator app that uses Templated MCP to create images. Users should be able to enter a headline and select a template, then generate and download the image. See the Templated MCP documentation at for setup instructions.” These AI tools can automatically set up the MCP connection, create the UI, and handle the image generation workflow—all from a simple prompt. ## Connection Modes [Section titled “Connection Modes”](#connection-modes) The Templated MCP server supports two connection modes: Remote Server (Recommended) Connect directly to our hosted MCP server at `mcp.templated.io`. No installation required—just add the URL to your AI assistant’s configuration. **Best for:** ChatGPT, Cursor, quick setup Local Server Run the MCP server locally using `npx`. The server runs on your machine and connects to our API. **Best for:** Claude Desktop, offline development ## Quick Start [Section titled “Quick Start”](#quick-start) * Remote Server Add this configuration to your AI assistant: ```json { "mcpServers": { "templated": { "url": "https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY" } } } ``` Replace `YOUR_API_KEY` with your [API key](https://app.templated.io/api-key). * Local Server Add this configuration to your AI assistant: ```json { "mcpServers": { "templated": { "command": "npx", "args": ["mcp-server-templated"], "env": { "TEMPLATED_API_KEY": "YOUR_API_KEY" } } } } ``` Replace `YOUR_API_KEY` with your [API key](https://app.templated.io/api-key). Note Local mode requires Node.js 18+ installed on your machine. ## Supported AI Assistants [Section titled “Supported AI Assistants”](#supported-ai-assistants) | Assistant | Remote Server | Local Server | | --------------- | :-----------: | :----------: | | Claude Desktop | ✓ | ✓ | | Cursor | ✓ | ✓ | | ChatGPT | ✓ | — | | Claude.ai (web) | ✓ | — | ## What You Can Do [Section titled “What You Can Do”](#what-you-can-do) ### Generate Content [Section titled “Generate Content”](#generate-content) * Create images, PDFs, and videos from templates * Customize layer properties (text, images, colors, positions) * Batch render multiple variations * Merge multiple renders into a single PDF ### Manage Templates [Section titled “Manage Templates”](#manage-templates) * List all your templates * Create new templates programmatically * Update template properties and layers * Clone templates for variations * Delete templates you no longer need ### Organize Assets [Section titled “Organize Assets”](#organize-assets) * Upload images and fonts * Create and manage folders * Move templates and renders between folders * View account information and usage ### Multi-Tenant Access [Section titled “Multi-Tenant Access”](#multi-tenant-access) * Scope access by **folder** or **external ID** to isolate resources per customer * Enforce access control at the server level, immune to prompt injection * Ideal for building customer-facing chat interfaces on top of Templated [Learn more about scoping access →](/docs/integrations/mcp/setup/#scoping-access) ## Example Prompts [Section titled “Example Prompts”](#example-prompts) Try these prompts with your AI assistant: “List all my Templated templates" "Create a render from template \[ID] with the headline ‘New Product Launch’" "Generate a transparent PNG from my logo template" "Create a new template called ‘Social Post’ with dimensions 1080x1080" "Clone my Instagram template and rename it to ‘TikTok Post’" "Show my API usage and account information” ## Resources [Section titled “Resources”](#resources) Setup Guide Step-by-step instructions for each AI assistant. [View Setup Guide →](/docs/integrations/mcp/setup/) Available Tools Complete reference of all 25+ MCP tools. [View Tools Reference →](/docs/integrations/mcp/tools/) GitHub Repository Source code, issues, and contributions. [View on GitHub →](https://github.com/templated-io/mcp-server-templated) npm Package Install the local server via npm. [View on npm →](https://www.npmjs.com/package/mcp-server-templated) # MCP Setup Guide > Step-by-step instructions to set up the Templated MCP server with Claude Desktop, Cursor, ChatGPT, and other AI assistants. This guide walks you through setting up the Templated MCP server with different AI assistants. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Before you begin, make sure you have: 1. A Templated account — [Sign up for free](https://app.templated.io/signup) 2. Your API key — Find it in your [dashboard](https://app.templated.io/api-key) For local server mode, you’ll also need: * Node.js 18 or higher installed ## Claude Desktop [Section titled “Claude Desktop”](#claude-desktop) Claude Desktop supports both remote and local MCP servers. ### Option 1: Local Server (Recommended for Claude Desktop) [Section titled “Option 1: Local Server (Recommended for Claude Desktop)”](#option-1-local-server-recommended-for-claude-desktop) 1. **Locate your config file** The Claude Desktop configuration file is located at: * **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json` * **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` 2. **Edit the configuration** Open the file and add the Templated MCP server: claude\_desktop\_config.json ```json { "mcpServers": { "templated": { "command": "npx", "args": ["mcp-server-templated"], "env": { "TEMPLATED_API_KEY": "YOUR_API_KEY" } } } } ``` Replace `YOUR_API_KEY` with your actual API key. 3. **Restart Claude Desktop** Completely quit and reopen Claude Desktop for the changes to take effect. 4. **Verify the connection** Look for a tools icon (hammer) in the chat input area. Click it to see available Templated tools. ### Option 2: Remote Server [Section titled “Option 2: Remote Server”](#option-2-remote-server) 1. **Locate your config file** Same location as above. 2. **Edit the configuration** claude\_desktop\_config.json ```json { "mcpServers": { "templated": { "url": "https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY" } } } ``` 3. **Restart Claude Desktop** Completely quit and reopen Claude Desktop. Tip If you have existing MCP servers configured, add `"templated"` to the existing `mcpServers` object rather than replacing the entire file. ## Cursor IDE [Section titled “Cursor IDE”](#cursor-ide) Cursor supports MCP servers through its configuration file. ### Remote Server (Recommended) [Section titled “Remote Server (Recommended)”](#remote-server-recommended) 1. **Locate your config file** The Cursor MCP configuration file is located at: * **macOS/Linux:** `~/.cursor/mcp.json` * **Windows:** `%USERPROFILE%\.cursor\mcp.json` 2. **Create or edit the configuration** mcp.json ```json { "mcpServers": { "templated": { "url": "https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY" } } } ``` 3. **Restart Cursor** Close and reopen Cursor for the changes to take effect. 4. **Start using Templated** In the Composer or Chat panel, you can now ask Cursor to use Templated tools. ### Local Server [Section titled “Local Server”](#local-server) 1. **Locate your config file** Same location as above. 2. **Edit the configuration** mcp.json ```json { "mcpServers": { "templated": { "command": "npx", "args": ["mcp-server-templated"], "env": { "TEMPLATED_API_KEY": "YOUR_API_KEY" } } } } ``` 3. **Restart Cursor** ## ChatGPT [Section titled “ChatGPT”](#chatgpt) ChatGPT supports MCP servers through Connected Apps in the settings. 1. **Open ChatGPT Settings** Go to **Settings** → **Connected Apps** → **Add MCP Server** 2. **Enter the server URL** ```plaintext https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY ``` Replace `YOUR_API_KEY` with your actual API key. 3. **Set authentication to “No Auth”** Since the API key is included in the URL, select **“No Auth”** for authentication type. 4. **Click Create** ChatGPT will verify the connection and add Templated to your connected apps. 5. **Start using Templated** In any conversation, you can now ask ChatGPT to use Templated tools to generate images, manage templates, and more. Note ChatGPT only supports remote MCP servers. The local server option is not available for ChatGPT. ## Claude.ai (Web) [Section titled “Claude.ai (Web)”](#claudeai-web) Claude.ai web interface also supports MCP servers. 1. **Go to Settings** Click on your profile icon and navigate to **Settings** → **Developer** → **MCP Servers** 2. **Add a new server** Click **Add Server** and enter: * **Name:** Templated * **URL:** `https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY` 3. **Save and start chatting** The Templated tools will now be available in your conversations. ## Scoping Access [Section titled “Scoping Access”](#scoping-access) When building multi-tenant applications (e.g. a chat interface where each customer edits their own templates), you can scope the MCP server so that each session only has access to a specific subset of resources. This is enforced at the server level, making it immune to prompt injection. You can scope by **folder ID**, **external ID**, or both. ### External ID Scoping [Section titled “External ID Scoping”](#external-id-scoping) If you already use `externalId` to link templates to your own customers (e.g. via the [Embedded Editor](/docs/embed/)), you can use the same identifier to scope MCP access. When set, the MCP server will: * Only list templates and renders matching that external ID * Automatically assign the external ID to new templates * Reject any operation on a template that doesn’t match - Remote Server Add the `externalId` query parameter to the URL: ```plaintext https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY&externalId=CUSTOMER_123 ``` - Local Server Set the `TEMPLATED_EXTERNAL_ID` environment variable: ```json { "mcpServers": { "templated": { "command": "npx", "args": ["mcp-server-templated"], "env": { "TEMPLATED_API_KEY": "YOUR_API_KEY", "TEMPLATED_EXTERNAL_ID": "CUSTOMER_123" } } } } ``` ### Folder ID Scoping [Section titled “Folder ID Scoping”](#folder-id-scoping) You can also restrict access to a specific folder. When set, the MCP server will: * Only list templates and renders from that folder * Automatically move new templates into the folder * Reject any operation on a template outside the folder * Hide folder management tools (since the folder is fixed) - Remote Server Add the `folderId` query parameter to the URL: ```plaintext https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY&folderId=FOLDER_ID ``` - Local Server Set the `TEMPLATED_FOLDER_ID` environment variable: ```json { "mcpServers": { "templated": { "command": "npx", "args": ["mcp-server-templated"], "env": { "TEMPLATED_API_KEY": "YOUR_API_KEY", "TEMPLATED_FOLDER_ID": "FOLDER_ID" } } } } ``` ### Combining Both [Section titled “Combining Both”](#combining-both) You can use both scoping parameters together for stricter isolation. For example, to restrict access to a specific folder AND external ID: ```plaintext https://mcp.templated.io/mcp?apiKey=YOUR_API_KEY&folderId=FOLDER_ID&externalId=CUSTOMER_123 ``` Tip For most multi-tenant use cases, **external ID scoping alone is sufficient**. It maps directly to your customer/user identifier and doesn’t require managing a folder per customer. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### Server not connecting [Section titled “Server not connecting”](#server-not-connecting) Common Issues * **Invalid API key:** Double-check your API key is correct * **JSON syntax error:** Validate your config file is valid JSON * **Node.js not found:** For local server, ensure Node.js 18+ is installed and in your PATH * **Server timeout:** Check your internet connection ### Tools not appearing [Section titled “Tools not appearing”](#tools-not-appearing) If the tools don’t appear after configuration: 1. **Completely restart** the AI assistant (not just close the window) 2. **Check the config file location** — it must be in the exact path specified 3. **Verify JSON syntax** — use a JSON validator to check for errors 4. **Check for existing configs** — you may need to merge with existing `mcpServers` ### Local server errors [Section titled “Local server errors”](#local-server-errors) If using local server mode: ```bash # Verify Node.js version node --version # Should be 18.0.0 or higher # Test the MCP server directly TEMPLATED_API_KEY=your_key npx mcp-server-templated ``` ### Getting help [Section titled “Getting help”](#getting-help) If you’re still having issues: * Check our [GitHub Issues](https://github.com/templated-io/mcp-server-templated/issues) * Contact us at [](mailto:support@templated.io) # MCP Tools Reference > Complete reference of all available tools in the Templated MCP server. The Templated MCP server provides 25+ tools that cover the full Templated API. This page documents all available tools and their parameters. ## Render Tools [Section titled “Render Tools”](#render-tools) Tools for creating and managing renders (generated images, videos, and PDFs). ### create\_render [Section titled “create\_render”](#create_render) Creates a new render from a template. | Parameter | Type | Required | Description | | ------------- | ------- | :------: | -------------------------------------------------------------------------------------------------------- | | `template` | string | ✓ | Template ID to render | | `layers` | object | — | Layer modifications (key: layer name, value: properties). Supports `animation` object for video renders. | | `format` | string | — | Output format: `jpg`, `png`, `webp`, `pdf`, `mp4` (default: `jpg`) | | `transparent` | boolean | — | Make background transparent (PNG only) | | `width` | number | — | Custom width in pixels | | `height` | number | — | Custom height in pixels | | `name` | string | — | Custom name for the render | | `webhook_url` | string | — | URL to POST render result to | | `duration` | number | — | Video duration in milliseconds (MP4 only, max 90000) | | `fps` | number | — | Frames per second (MP4 only, 1-60) | **Example prompt:** > “Create a render from template abc123 with the title layer set to ‘Hello World’ and format as PNG” ### get\_render [Section titled “get\_render”](#get_render) Retrieves details of a specific render. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ----------- | | `id` | string | ✓ | Render ID | ### list\_renders [Section titled “list\_renders”](#list_renders) Lists all renders, optionally filtered. | Parameter | Type | Required | Description | | ------------ | ------ | :------: | -------------------------------------- | | `limit` | number | — | Maximum number to return (default: 20) | | `templateId` | string | — | Filter by template ID | | `folderId` | string | — | Filter by folder ID | ### delete\_render [Section titled “delete\_render”](#delete_render) Deletes a render. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------- | | `id` | string | ✓ | Render ID to delete | Caution This action is irreversible. The render file will be permanently deleted. ### merge\_renders [Section titled “merge\_renders”](#merge_renders) Merges multiple renders into a single PDF. | Parameter | Type | Required | Description | | ----------- | ------ | :------: | ---------------------------- | | `renderIds` | array | ✓ | Array of render IDs to merge | | `name` | string | — | Name for the merged PDF | ## Template Tools [Section titled “Template Tools”](#template-tools) Tools for managing templates. ### list\_templates [Section titled “list\_templates”](#list_templates) Lists all templates in your account. | Parameter | Type | Required | Description | | ---------- | ------ | :------: | -------------------------------------- | | `limit` | number | — | Maximum number to return (default: 20) | | `folderId` | string | — | Filter by folder ID | | `tags` | array | — | Filter by tags | ### get\_template [Section titled “get\_template”](#get_template) Retrieves details of a specific template. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ----------- | | `id` | string | ✓ | Template ID | ### get\_template\_layers [Section titled “get\_template\_layers”](#get_template_layers) Gets all layers in a template with their properties. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ----------- | | `id` | string | ✓ | Template ID | **Example prompt:** > “Show me all the layers in template abc123” ### get\_template\_pages [Section titled “get\_template\_pages”](#get_template_pages) Gets all pages in a multi-page template. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ----------- | | `id` | string | ✓ | Template ID | ### create\_template [Section titled “create\_template”](#create_template) Creates a new template programmatically. | Parameter | Type | Required | Description | | ------------ | ------ | :------: | ---------------------------------------------------- | | `name` | string | ✓ | Template name | | `width` | number | ✓ | Width in pixels | | `height` | number | ✓ | Height in pixels | | `background` | string | — | Background color (hex) | | `duration` | number | — | Default video duration in milliseconds (MP4 renders) | | `layers` | array | — | Array of layer objects | | `folderId` | string | — | Folder to create template in | **Layer object properties:** | Property | Type | Description | | --------------- | ------ | ----------------------------------------------- | | `layer` | string | Unique layer name (required) | | `type` | string | Layer type: `text`, `image`, `shape` (required) | | `x` | number | X position | | `y` | number | Y position | | `width` | number | Layer width | | `height` | number | Layer height | | `text` | string | Text content (for text layers) | | `color` | string | Text color (hex) | | `font_family` | string | Font family name | | `font_size` | string | Font size (e.g., “24px”) | | `image_url` | string | Image URL (for image layers) | | `background` | string | Background color (hex) | | `border_radius` | string | Border radius (e.g., “10px”) | | `animation` | object | Animation config for video renders (see below) | **Animation object properties** (MP4 only): | Property | Type | Description | | -------- | ------- | ------------------------------------------------------------------------------------------------------------ | | `in` | object | Entrance animation: `type` (`slide`, `fade`, `zoom`, `rotate`), `direction`, `duration` (ms), `writingStyle` | | `loop` | object | Looping animation: `type` (`spin`, `pulse`), `duration` (ms) | | `out` | object | Exit animation: `type` (`slide`, `fade`, `zoom`), `direction`, `duration` (ms) | | `start` | integer | Time in milliseconds when layer becomes visible (default: 0) | | `end` | integer | Time in milliseconds when layer disappears (default: video duration) | **Example prompt:** > “Create a new template called ‘Social Post’ that’s 1080x1080 with a blue background and a white text layer for the title” ### update\_template [Section titled “update\_template”](#update_template) Updates an existing template. | Parameter | Type | Required | Description | | ------------ | ------ | :------: | -------------------------------------- | | `id` | string | ✓ | Template ID | | `name` | string | — | New template name | | `width` | number | — | New width | | `height` | number | — | New height | | `background` | string | — | New background color | | `duration` | number | — | Default video duration in milliseconds | | `layers` | array | — | Updated layers | ### clone\_template [Section titled “clone\_template”](#clone_template) Creates a copy of a template. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ---------------------------- | | `id` | string | ✓ | Template ID to clone | | `name` | string | — | Name for the cloned template | **Example prompt:** > “Clone my Instagram template and name it ‘TikTok Version‘“ ### delete\_template [Section titled “delete\_template”](#delete_template) Deletes a template. | Parameter | Type | Required | Description | | --------- | ------ | :------: | --------------------- | | `id` | string | ✓ | Template ID to delete | Caution This action is irreversible. All renders associated with the template will remain, but you won’t be able to create new renders from it. ### list\_template\_renders [Section titled “list\_template\_renders”](#list_template_renders) Lists all renders created from a specific template. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------------ | | `id` | string | ✓ | Template ID | | `limit` | number | — | Maximum number to return | ## Folder Tools [Section titled “Folder Tools”](#folder-tools) Tools for organizing templates and renders into folders. ### list\_folders [Section titled “list\_folders”](#list_folders) Lists all folders. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------------ | | `limit` | number | — | Maximum number to return | ### create\_folder [Section titled “create\_folder”](#create_folder) Creates a new folder. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------ | | `name` | string | ✓ | Folder name | | `color` | string | — | Folder color (hex) | ### update\_folder [Section titled “update\_folder”](#update_folder) Updates a folder’s name or color. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ---------------- | | `id` | string | ✓ | Folder ID | | `name` | string | — | New folder name | | `color` | string | — | New folder color | ### delete\_folder [Section titled “delete\_folder”](#delete_folder) Deletes a folder. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------- | | `id` | string | ✓ | Folder ID to delete | Note Deleting a folder moves its contents to the root level, not to trash. ## Upload Tools [Section titled “Upload Tools”](#upload-tools) Tools for managing uploaded images. ### list\_uploads [Section titled “list\_uploads”](#list_uploads) Lists all uploaded images. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------------ | | `limit` | number | — | Maximum number to return | ### create\_upload [Section titled “create\_upload”](#create_upload) Uploads an image from a URL. | Parameter | Type | Required | Description | | --------- | ------ | :------: | -------------------------- | | `url` | string | ✓ | URL of the image to upload | | `name` | string | — | Name for the upload | **Example prompt:** > “Upload this image logo.png to my Templated account” ### delete\_upload [Section titled “delete\_upload”](#delete_upload) Deletes an uploaded image. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------- | | `id` | string | ✓ | Upload ID to delete | ## Font Tools [Section titled “Font Tools”](#font-tools) Tools for managing custom fonts. ### list\_fonts [Section titled “list\_fonts”](#list_fonts) Lists all uploaded custom fonts. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------------ | | `limit` | number | — | Maximum number to return | ### upload\_font [Section titled “upload\_font”](#upload_font) Uploads a custom font from a URL. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ------------------------------------------------ | | `url` | string | ✓ | URL of the font file (.ttf, .otf, .woff, .woff2) | | `name` | string | — | Name for the font | ### delete\_font [Section titled “delete\_font”](#delete_font) Deletes a custom font. | Parameter | Type | Required | Description | | --------- | ------ | :------: | ----------------- | | `id` | string | ✓ | Font ID to delete | ## Account Tools [Section titled “Account Tools”](#account-tools) ### get\_account [Section titled “get\_account”](#get_account) Retrieves account information including usage statistics. No parameters required. **Returns:** * Account name and email * Current plan * API usage statistics * Remaining credits **Example prompt:** > “Show me my Templated account information and usage” ## Tool Categories Summary [Section titled “Tool Categories Summary”](#tool-categories-summary) | Category | Tools | Description | | ------------- | ----- | --------------------------------------------- | | **Renders** | 5 | Create, view, list, delete, and merge renders | | **Templates** | 9 | Full template lifecycle management | | **Folders** | 4 | Organize content into folders | | **Uploads** | 3 | Manage uploaded images | | **Fonts** | 3 | Manage custom fonts | | **Account** | 1 | View account information | Tip When asking your AI assistant to use these tools, you don’t need to use the exact parameter names. Natural language works great! For example, instead of saying: > “Use create\_render with template=abc123 and format=png” You can simply say: > “Create a PNG from template abc123” # Create a render > Learn to create a render (image, PDF, or video) using the Templated API. What is a render? A render is the generated output of a template.\ It can be an image, video, or PDF. This is the endpoint to create a render. It responds with `200 OK` and returns the render data including the render URL.\ By default, renders are generated synchronously and take around 2 seconds to complete (videos may take longer depending on duration and complexity). Once generated, the image/PDF/video file is immediately available at the returned URL. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to create a render: ENDPOINT ```js POST /v1/render; ``` * JavaScript ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify( { "template" : TEMPLATE_ID, "layers" : { "text-1" : { "text" : "This is my text to be rendered", "color" : "#FF0000", "background" : "#0000FF" }, "image-1": { "image_url" : "https://picsum.photos/200/300.jpg" } } } ), headers: { 'Content-Type' : 'application/json', 'Authorization' : `Bearer ${API_KEY}` } }) ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'TEMPLATE_ID' url = 'https://api.templated.io/v1/render' headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {api_key}' } data = { 'template': template_id, 'layers': { 'text-1': { 'text': 'This is my text to be rendered', 'color': '#FF0000', 'background': '#0000FF' }, 'image-1': { 'image_url': 'https://picsum.photos/200/300.jpg' } } } response = requests.post(url, json=data, headers=headers) if response.status_code == 200: print('Render request accepted.') else: print('Render request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import org.json.JSONObject; public class RenderRequest { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "TEMPLATE_ID"; URL url = new URL("https://api.templated.io/v1/render"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); connection.setDoOutput(true); JSONObject layers = new JSONObject() .put("text-1", new JSONObject() .put("text", "This is my text to be rendered") .put("color", "#FF0000") .put("background", "#0000FF")) .put("image-1", new JSONObject() .put("image_url", "https://picsum.photos/200/300.jpg")); JSONObject jsonInput = new JSONObject() .put("template", templateId) .put("layers", layers); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonInput.toString().getBytes("utf-8"); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); System.out.println(responseCode); } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php $templateId, 'layers' => [ 'text-1' => [ 'text' => 'This is my text to be rendered', 'color' => '#FF0000', 'background' => '#0000FF' ], 'image-1' => [ 'image_url' => 'https://picsum.photos/200/300.jpg' ] ] ]; $options = [ 'http' => [ 'header' => [ 'Content-Type: application/json', 'Authorization: Bearer ' . $apiKey ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { // Handle error } echo $result; ?> ``` * cURL ```bash curl -X POST https://api.templated.io/v1/render \ -H "Content-Type: application/json" \ -H "Authorization: Bearer API_KEY" \ -d '{ "template": "TEMPLATE_ID", "layers": { "text-1": { "text": "This is my text to be rendered", "color": "#FF0000", "background": "#0000FF" }, "image-1": { "image_url": "https://picsum.photos/200/300.jpg" } } }' ``` ## Parameters [Section titled “Parameters”](#parameters) template `string` `REQUIRED`\ The template id that you want to render. templates `array`\ This is only used for batch rendering from a list of templates.\ If it’s provided, the template parameter will be ignored and will not be required.\ Example: `"templates": ["template-id-1", "template-id-2"]` format `string`\ Render format (`jpg`, `png`, `webp`, `pdf`, `mp4`, or `html`). Default is `jpg`.\ `html` exports the rendered template as a static HTML file and is available on Enterprise plans only. transparent `boolean`\ Make the background transparent when the render format is `png`. Default is `false`. duration `number`\ Duration of the video in milliseconds when the render format is `mp4`.\ Maximum is 90000 (90 seconds). Default is 5000 (5 seconds). fps `number`\ Frames per second when the render format is `mp4`.\ Minimum is `1`. Maximum is `60`. Default is `30`. flatten `boolean`\ Flatten the PDF when the render format is `pdf`.\ This is recommended for print-ready documents. Default is `false`. cmyk `boolean`\ Use CMYK color mode when the render format is `pdf`.\ This is recommended for print-ready documents. Default is `false`. name `string`\ A custom name for the render. background `string`\ Background color in hex format e.g. “#FF0000”. width `number`\ A custom width for the render in pixels (minimum 100, maximum 5000). height `number`\ A custom height for the render in pixels (minimum 100, maximum 5000). scale `number`\ Scale factor to resize the final render (minimum `0.1`, maximum `2.0`).\ For example, `0.5` will render at 50% size, `2.0` will render at 200% size. Default is `1.0`. external\_id `string`\ An external identifier to associate the render with a specific user or entity in your system. async `boolean`\ If set to `false`, the render will be created synchronously. Default is `false`. webhook\_url `string`\ A url to POST the full Render object to upon rendering completed. merge `boolean`\ When set to `true` and multiple renders are generated (multi-page templates), automatically merge all renders into a single PDF. Default is `false`. zip `boolean`\ When set to `true` and multiple renders are generated (multi-page templates or the `templates` array), bundle every render into a single ZIP archive and return its URL. Each render is added as an individual file in its original format. Cannot be combined with `merge`. Default is `false`. pages `array`\ For multi-page templates, use this to specify different layer modifications for each page.\ Each object in the array should have a `page` (page identifier) and `layers` (layer modifications for that page).\ You can optionally include `width` and `height` to override the dimensions of individual pages.\ When using `pages`, the `layers` parameter is ignored. layers `object`\ An object of layers that will be updated in the template.\ The object key is the layer name and the value is an object with the layer properties to override.\ Use this for single-page templates or to apply the same changes to all pages in multi-page templates. ### Layer Parameters [Section titled “Layer Parameters”](#layer-parameters) These are the parameters that can be used to override the template layers attributes. text `string`\ Replacement text you want to use.\ If the layer is a QR Code or a Barcode this will be the value used. image\_url `string`\ Replacement image src for an image layer. color `string`\ Color in hex format e.g. “#FF0000”. color\_2 `string`\ Secondary color in hex format. It will be applied to text surrounded by `*` in the text layer. background `string`\ Background color in hex format e.g. “#FF0000”. font\_family `string`\ Change the font family. font\_family\_2 `string`\ Secondary font family. It will be applied to text surrounded by `*` in the text layer. font\_size `string`\ Change the font size. Use a CSS value like (“24px” or “12pt”).\ An explicit font size takes precedence over `autofit` — omit `font_size` if you want autofit to control the size. font\_weight `string`\ Change the font weight (normal, bold, 100, 200, 300, 400, 500, 600, 700, 800, 900). letter\_spacing `string`\ Change the letter spacing of the text. Accepts CSS values like “2.5px”, “0.5em”, or “-1px”. Can be negative. line\_height `string`\ Change the line height of the text. Accepts CSS values like “1.5” (unitless multiplier), “24px”, or “2em”. text\_stroke\_width `double`\ Width of the text stroke (outline) in pixels. Use this to add an outline to your text. text\_stroke\_color `string`\ Color of the text stroke (outline) in hex format e.g. “#000000”. text\_highlight\_color `string`\ Background color of the text highlight in hex format e.g. “#FFFF00”.\ Only applies to text layers that have text highlight enabled. padding\_x `integer`\ Horizontal padding in pixels. padding\_y `integer`\ Vertical padding in pixels. horizontal\_align `string`\ Change the horizontal alignment of the text (left, center, right). vertical\_align `string`\ Change the vertical alignment of the text (top, center, bottom). autofit `string`\ Set to “width” or “height” to automatically fit the text to the width or height of the layer box.\ The box defaults to the dimensions defined in the Editor; passing `width`/`height` in the request overrides it.\ Do not combine with `font_size` — an explicit font size takes precedence and disables autofit. Use `max_font_size` instead to keep a consistent size across renders while still shrinking text that is too long. min\_font\_size `double`\ Minimum font size in pixels used by autofit when shrinking the text.\ Set to `0` to remove the minimum and let autofit shrink the text as much as needed. max\_font\_size `double`\ Maximum font size in pixels used by autofit when growing the text.\ Set to `0` to remove the maximum. border\_width `integer`\ Width of the object border. border\_color `string`\ Border color in hex format e.g. “#FF0000”. border\_radius `string`\ Border radius in px or percentage (e.g. “10px” or “10%”). border\_style `string`\ Border style for shapes and lines (solid, dashed, dotted). Default is “solid”. dash\_length `double`\ Custom dash/dot length for dashed or dotted border styles. If not provided, defaults are calculated based on stroke width. dash\_gap `double`\ Custom gap length between dashes or dots for dashed or dotted border styles. If not provided, defaults are calculated based on stroke width. fill `string`\ Fill color for shapes and uploaded SVG components.\ Supports hex colors (e.g. “#FF0000”) and CSS linear gradients (e.g. “linear-gradient(90deg, #FF0000 0%, #0000FF 100%)”). stroke `string`\ Stroke (border) color for shapes and uploaded SVG components in hex format e.g. “#FF0000”. preserve\_ratio `boolean`\ Set to `false` to allow free scaling of SVG shapes and vectors without preserving the aspect ratio.\ When `false`, the SVG content will stretch to fill the layer dimensions. Default is `true`. hide `boolean`\ Set to true to hide the layer. locked `boolean`\ Set to `true` to lock the layer or `false` to unlock it (make it flexible).\ Locked layers are hidden from the [Get layers](/docs/templates/layers/) endpoint by default and cannot be edited in the Editor.\ Only used when [creating](/docs/templates/create/) or [updating](/docs/templates/update/) a template — it has no effect on renders. When updating, omitting the property leaves the current locked state unchanged. opacity `double`\ Set the opacity of the layer. Value should be between 0 (fully transparent) and 1 (fully visible). link `string`\ Add a link to the layer. It must start with `http://` or `https://`.\ Links will only work on PDF renders. x `integer`\ Horizontal position of the layer (top left corner). y `integer`\ Vertical position of the layer (top left corner). rotation `integer`\ Rotation of the layer in degrees. width `integer`\ Width of the layer. height `integer`\ Height of the layer. flip\_x `boolean`\ Flip the layer horizontally. Set to `true` to mirror the layer along the Y-axis. flip\_y `boolean`\ Flip the layer vertically. Set to `true` to mirror the layer along the X-axis. object\_fit `string`\ Change the object fit of an image (cover, contain, fill, none). object\_position `string`\ Change the alignment of an image within its container when using `object_fit: "cover"` or `"contain"`.\ Accepts CSS object-position values like `"center"`, `"top"`, `"bottom left"`, `"25% 75%"`, etc. crop\_x `double`\ The X position of the crop area as a percentage (0–100). Use together with `crop_width` and `crop_height` to crop an image layer. crop\_y `double`\ The Y position of the crop area as a percentage (0–100). crop\_width `double`\ The width of the crop area as a percentage (0–100). For example, `50` means the crop area covers 50% of the image width. crop\_height `double`\ The height of the crop area as a percentage (0–100). For example, `50` means the crop area covers 50% of the image height. filter `string`\ Change the filter of an image layer.\ Example: `"blur(4px) brightness(68%) hue-rotate(27deg) contrast(70%) saturate(125%) sepia(53%) grayscale(27%) invert(25%)"` blend\_mode `string`\ Set how an image layer blends with the layers beneath it (CSS `mix-blend-mode`).\ Supported values: `normal`, `multiply`, `screen`, `overlay`, `darken`, `lighten`, `color-dodge`, `color-burn`, `hard-light`, `soft-light`, `difference`, `exclusion`, `hue`, `saturation`, `color`, `luminosity`. barcode\_format `string`\ The format of the barcode.\ Supported formats: CODE128, CODE39, EAN13, EAN8, ITF14, UPC. rating `double`\ The rating of the star rating layer. html `string`\ Set the layer content to a custom HTML content.\ Value example: `"
  • Item 1
  • Item 2
  • Item 3
"` animation `object`\ Animation configuration for video (MP4) renders. Contains the following properties: * in `object` — Entrance animation. Properties: * `type` `string` — Animation type: `slide`, `fade`, `zoom`, `rotate` * `direction` `string` — Direction: `left`, `right`, `up`, `down` (for slide), `in`, `out` (for zoom) * `duration` `integer` — Duration in milliseconds * `writingStyle` `string` — Text animation style: `block`, `word`, `character` (text layers with slide/fade) * loop `object` — Looping animation. Properties: * `type` `string` — Animation type: `spin`, `pulse` * `duration` `integer` — Duration in milliseconds per cycle * out `object` — Exit animation. Properties: * `type` `string` — Animation type: `slide`, `fade`, `zoom` * `direction` `string` — Direction: `left`, `right`, `up`, `down` (for slide), `in`, `out` (for zoom) * `duration` `integer` — Duration in milliseconds * start `integer` — Time in milliseconds when the layer becomes visible (default: `0`) * end `integer` — Time in milliseconds when the layer disappears (default: video duration) ## Response [Section titled “Response”](#response) The API returns a JSON object with the render details. ```json { "id": "ce424057-6b54-41bb-afec-adc35a2b9175", "url": "https://cdn.templated.media/render/ce424057-6b54-41bb-afec-adc35a2b9175.jpg", "storage_url": "https://assets.yourcompany.com/renders/ce424057-6b54-41bb-afec-adc35a2b9175.jpg", "width": 1920, "height": 1080, "format": "jpg", "templateId": "1f1231-dasd123-fsdf12312-fds4123-asdas23", "templateName": "Sample Template", "createdAt": "2025-04-22 08:30:58", "externalId": null } ``` ### Response Fields [Section titled “Response Fields”](#response-fields) * `id`: Unique identifier for the render. * `url`: URL where the render is accessible. Points to Templated’s CDN by default, or to your bucket if **Store only in my bucket** mode is enabled with custom storage. * `storage_url`: URL of the copy delivered to your own bucket when [Custom Storage](/docs/integrations/custom-storage) is connected; `null` otherwise. * `width`: Render width in pixels. * `height`: Render height in pixels. * `format`: Output format (jpg, png, webp, pdf, or mp4). * `templateId`: ID of the template that was rendered. * `templateName`: Name of the template. * `createdAt`: Timestamp when the render was created. * `externalId`: External identifier if provided in the render request. Tweak a render after the fact Need to adjust a render’s result (move a text, crop an image) and render it again? Use the [Create template from render](/docs/templates/create-from-render/) endpoint to get an editable clone template with that render’s modifications applied. ## Multi-Page Template [Section titled “Multi-Page Template”](#multi-page-template) If you are using a multi-page template, you can use the `pages` parameter to specify different layer modifications for each page.\ Multi-page templates are ideal for creating carousels or PDF documents with multiple pages. API Quota Each page render counts as 1 credit toward your API quota. ### Same Content Across All Pages [Section titled “Same Content Across All Pages”](#same-content-across-all-pages) Similarly to the single-page template, you can use the `layers` parameter to apply the same modifications to all pages: ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify({ "template": TEMPLATE_ID, "layers": { "company_name": { "text": "ACME Corporation" }, "logo": { "image_url": "https://example.com/logo.png" } } }), headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Different Content Per Page [Section titled “Different Content Per Page”](#different-content-per-page) Use the `pages` parameter to specify different layer modifications for each page.\ You can even duplicate the same page multiple times to create a carousel. * JavaScript ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify({ "template": TEMPLATE_ID, "pages": [ { "page": "page-1", "layers": { "title": { "text": "Welcome to Our Company" }, "subtitle": { "text": "Page 1 Content" } } }, { "page": "page-2", "layers": { "title": { "text": "Our Services" }, "content": { "text": "We offer amazing services..." } } }, { "page": "page-3", "layers": { "title": { "text": "Contact Us" }, "contact": { "text": "support@company.com" } } } ] }), headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` } }) ``` * Python ```python import requests data = { 'template': 'TEMPLATE_ID', 'pages': [ { 'page': 'page-1', 'layers': { 'title': {'text': 'Welcome to Our Company'}, 'subtitle': {'text': 'Page 1 Content'} } }, { 'page': 'page-2', 'layers': { 'title': {'text': 'Our Services'}, 'content': {'text': 'We offer amazing services...'} } }, { 'page': 'page-3', 'layers': { 'title': {'text': 'Contact Us'}, 'contact': {'text': 'support@company.com'} } } ] } response = requests.post( 'https://api.templated.io/v1/render', json=data, headers={'Authorization': 'Bearer API_KEY'} ) ``` ### Different Dimensions Per Page [Section titled “Different Dimensions Per Page”](#different-dimensions-per-page) You can set different dimensions for each page using the `width` and `height` parameters inside each page object. This is useful for creating collections with mixed formats (e.g. a cover at 1920×1080, content at 1080×1080, and stories at 1080×1920). ```json { "template": "TEMPLATE_ID", "pages": [ { "page": "cover", "width": 1920, "height": 1080, "layers": { "title": { "text": "Welcome" } } }, { "page": "content", "width": 1080, "height": 1080, "layers": { "title": { "text": "Our Services" } } }, { "page": "story", "width": 1080, "height": 1920, "layers": { "title": { "text": "Follow Us" } } } ] } ``` If `width` or `height` is not specified for a page, it falls back to the dimensions set in the page’s HTML style, then to the global `width`/`height` parameters, and finally to the template’s default dimensions. ### Response for Multi-Page Templates [Section titled “Response for Multi-Page Templates”](#response-for-multi-page-templates) When multiple pages are rendered (using `pages` parameter or multi-page templates with `layers`), you will receive an array of render objects in the response: ```json [ { "id": "render-page1-id", "url": "https://cdn.templated.media/render/render-page1-id.jpg", "page": "page-1", "width": 1920, "height": 1080, "format": "jpg", "templateId": "template-id", "templateName": "Multi-Page Template", "createdAt": "2025-04-22 08:30:58" }, { "id": "render-page2-id", "url": "https://cdn.templated.media/render/render-page2-id.jpg", "page": "page-2", "width": 1920, "height": 1080, "format": "jpg", "templateId": "template-id", "templateName": "Multi-Page Template", "createdAt": "2025-04-22 08:30:58" } ] ``` Multi-Page Behavior • If your template has multiple pages but you use the `layers` parameter, the same layer modifications will be applied to **all pages**\ • Use the `pages` parameter when you need **different content per page**\ • You can loop through the pages to duplicate the same page multiple times\ • Set `"merge": true` to get a **single PDF** with multiple pages instead of separate images\ • Set `"zip": true` to get a **single ZIP archive** bundling each render as a separate file\ • Each page render counts toward your API quota ## Download All Pages as a ZIP [Section titled “Download All Pages as a ZIP”](#download-all-pages-as-a-zip) Set `"zip": true` to bundle every generated render into a single ZIP archive instead of receiving an array of separate URLs.\ This works with multi-page templates and with the `templates` array (batch rendering). Each render is added to the archive as an individual file in its original format (`jpg`, `png`, `pdf`, `mp4`, etc.). * JavaScript ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify({ "template": TEMPLATE_ID, "zip": true, "pages": [ { "page": "page-1", "layers": { "title": { "text": "Page 1" } } }, { "page": "page-2", "layers": { "title": { "text": "Page 2" } } } ] }), headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` } }) ``` * cURL ```bash curl -X POST https://api.templated.io/v1/render \ -H "Content-Type: application/json" \ -H "Authorization: Bearer API_KEY" \ -d '{ "template": "TEMPLATE_ID", "zip": true, "pages": [ { "page": "page-1", "layers": { "title": { "text": "Page 1" } } }, { "page": "page-2", "layers": { "title": { "text": "Page 2" } } } ] }' ``` The response contains the URL of the ZIP archive along with the individual render objects: ```json { "url": "https://templated-assets.s3.amazonaws.com/zip-renders/renders_2b8f1c9e.zip", "renders": [ { "id": "render-page1-id", "url": "...", "page": "page-1", "format": "jpg" }, { "id": "render-page2-id", "url": "...", "page": "page-2", "format": "jpg" } ] } ``` merge vs zip • Use **`merge`** to combine all pages into a **single PDF** document.\ • Use **`zip`** to bundle the renders as **separate files** inside one ZIP archive (each render keeps its original format).\ • `merge` and `zip` cannot be used in the same request.\ • When combining `zip` with `"async": true`, a `webhook_url` is **required** (the request returns `400` without it) — the ZIP URL is delivered via webhook once all pages finish rendering. ## Video Rendering [Section titled “Video Rendering”](#video-rendering) Beta Feature Video rendering is currently in **Beta**.\ Results may vary and we’re actively improving this feature. Templated supports rendering templates as MP4 videos. This is ideal for templates with animations, video layers, or when you want to create dynamic video content from your designs. ### Video Parameters [Section titled “Video Parameters”](#video-parameters) When rendering videos, you can control the following parameters: | Parameter | Type | Description | Default | | ---------- | ------ | ----------------------------------------------------------------------------------------------------------- | ------- | | `format` | string | Set to `"mp4"` for video output | `"jpg"` | | `duration` | number | Video duration in milliseconds (max 90000). Falls back to the template’s default duration if not specified. | `5000` | | `fps` | number | Frames per second (10, 30, or 60) | `30` | ### Sample Video Request [Section titled “Sample Video Request”](#sample-video-request) * JavaScript ```js fetch('https://api.templated.io/v1/render', { method: 'POST', body: JSON.stringify({ "template": TEMPLATE_ID, "format": "mp4", "duration": 10000, // 10 seconds "fps": 30, "layers": { "title": { "text": "Welcome to my video!" }, "background-video": { "video_url": "https://example.com/video.mp4" } } }), headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` } }) ``` * Python ```python import requests data = { 'template': 'TEMPLATE_ID', 'format': 'mp4', 'duration': 10000, # 10 seconds 'fps': 30, 'layers': { 'title': {'text': 'Welcome to my video!'}, 'background-video': {'video_url': 'https://example.com/video.mp4'} } } response = requests.post( 'https://api.templated.io/v1/render', json=data, headers={'Authorization': 'Bearer API_KEY'} ) ``` * cURL ```bash curl -X POST https://api.templated.io/v1/render \ -H "Content-Type: application/json" \ -H "Authorization: Bearer API_KEY" \ -d '{ "template": "TEMPLATE_ID", "format": "mp4", "duration": 10000, "fps": 30, "layers": { "title": { "text": "Welcome to my video!" }, "background-video": { "video_url": "https://example.com/video.mp4" } } }' ``` ### Layer Animations [Section titled “Layer Animations”](#layer-animations) You can add entrance, looping, and exit animations to any layer via the `animation` property. Animations only apply to video (MP4) renders. ```json { "template": "TEMPLATE_ID", "format": "mp4", "duration": 6000, "layers": { "title": { "text": "Breaking News", "animation": { "in": { "type": "slide", "direction": "left", "duration": 500 }, "loop": { "type": "pulse", "duration": 1000 }, "out": { "type": "fade", "duration": 500 }, "start": 1000, "end": 5000 } } } } ``` All time values in the `animation` object are in **milliseconds**, consistent with the top-level `duration` parameter. #### Animation Types [Section titled “Animation Types”](#animation-types) | Category | Types | Properties | | -------------------- | --------------------------------- | ----------------------------------------------- | | **in** (entrance) | `slide`, `fade`, `zoom`, `rotate` | `type`, `direction`, `duration`, `writingStyle` | | **loop** (repeating) | `spin`, `pulse` | `type`, `duration` | | **out** (exit) | `slide`, `fade`, `zoom` | `type`, `direction`, `duration` | **Direction values:** `left`, `right`, `up`, `down` (for slide) — `in`, `out` (for zoom) **Writing style** (text layers only): `block` (default), `word`, `character` — controls how text animates with slide/fade #### Timeline [Section titled “Timeline”](#timeline) The `start` and `end` properties control when a layer appears and disappears in the video: * `start` — time in milliseconds when the layer becomes visible (default: `0`) * `end` — time in milliseconds when the layer disappears (default: video duration) ### Video Credits Cost [Section titled “Video Credits Cost”](#video-credits-cost) Video rendering uses a credit system based on the template size, duration, and FPS.\ The formula is: Width × Height × FPS × Duration in seconds 50,000,000 **Example:** A 1920×1080 video at 30 FPS for 10 seconds would cost: * (1920 × 1080 × 30 × 10) / 50,000,000 = **12.4 credits** (rounded up to **13 credits**) #### Video Credit Usage Calculator [Section titled “Video Credit Usage Calculator”](#video-credit-usage-calculator) Use this calculator to estimate the number of credits required for a video render. Width (px)1920 Height (px)1080 FPS30 Duration (sec)10 Estimated Cost 13 credits (1920 × 1080 × 30 × 10) / 50M \= 6.22 → rounded up ### Limitations [Section titled “Limitations”](#limitations) Video Rendering Limitations • **Maximum duration:** 90 seconds\ • **FPS options:** 1-60 frames per second\ • **Processing time:** Videos take longer to render than images (typically 10-60 seconds depending on duration and complexity)\ • **File size:** Larger dimensions, higher FPS, and longer durations will result in larger file sizes\ • **Animations:** All CSS animations and video layers in your template will be captured in the output ### Best Practices for Video Rendering [Section titled “Best Practices for Video Rendering”](#best-practices-for-video-rendering) 1. **Start with shorter durations** - Test with 5-10 second videos before creating longer content 2. **Use appropriate FPS** - 30 FPS is suitable for most content; use 60 FPS only for smooth motion graphics 3. **Optimize template animations** - Ensure your animations are designed to loop or complete within the specified duration 4. **Consider async rendering** - For longer videos, set `"async": true` and use webhooks to be notified when rendering completes # Delete a render > Learn how to delete a render using the Templated API. Delete a specific render by its ID. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to delete a render: ENDPOINT ```js DELETE /v1/render/{id} ``` * JavaScript ```js fetch(`https://api.templated.io/v1/render/${RENDER_ID}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => { if (response.status === 204) { console.log('Render deleted successfully'); } }) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' render_id = 'RENDER_ID' url = f'https://api.templated.io/v1/render/{render_id}' headers = {'Authorization': f'Bearer {api_key}'} response = requests.delete(url, headers=headers) if response.status_code == 204: print('Render deleted successfully') else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; public class DeleteRender { public static void main(String[] args) { try { String apiKey = "API_KEY"; String renderId = "RENDER_ID"; URL url = new URL("https://api.templated.io/v1/render/" + renderId); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("DELETE"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_NO_CONTENT) { System.out.println("Render deleted successfully"); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = @file_get_contents($url, false, $context); if ($http_response_header[0] == 'HTTP/1.1 204 No Content') { echo "Render deleted successfully"; } else { echo "Error deleting render"; } ?> ``` ## Response [Section titled “Response”](#response) A successful deletion will return a `204 No Content` response with no body. ### Error Responses [Section titled “Error Responses”](#error-responses) | Status Code | Description | | ----------- | ----------------------------------------------------------- | | 401 | Not authorized - Invalid or missing API key | | 403 | Forbidden - You don’t have permission to delete this render | | 404 | Not Found - Render or user not found | | 500 | Internal Server Error - An unexpected error occurred | # Duplicate a render > Learn how to duplicate a render using the Templated API. Creates a duplicate of an existing render.\ The duplicated render will use the same template and payload as the original render and can be customized independently.\ Duplicating a render counts towards your API quota. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The render id of the render that you want to duplicate. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to duplicate a render: ENDPOINT ```js POST /v1/render/:id/duplicate ``` REQUEST ```js fetch(`https://api.templated.io/v1/render/${id}/duplicate`, { method: 'POST', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns a JSON object with the duplicated render details. ```json { "id": "new-render-id-456", "url": "https://cdn.templated.media/render/new-render-id-456.jpg", "width": 1920, "height": 1080, "format": "jpg", "status": "COMPLETED", "templateId": "template-id-123", "templateName": "Sample Template", "createdAt": "2024-01-15T10:30:00Z", } ``` # The render object > Learn the properties of a render object in the Templated API. A Render is what is generated when you render an image, PDF, or video from a template.\ On the next step you will learn how to create a render. Bellow are the basic attributes of a Render.\ All other attributes of the object are set by the user at the time of creation. ## Attributes [Section titled “Attributes”](#attributes) id `string`\ The unique ID for this object. width `number`\ The width of the rendered image in pixels. height `number`\ The height of the rendered image in pixels. url `string`\ The URL of the render. name `string`\ The name of the render. status `string`\ The current status of the render: PENDING, COMPLETED or FAILED. Initially the status is PENDING. format `string`\ The output format of the render. templateId `string`\ The ID of the template used to generate the render. templateName `string`\ The name of the template used to generate the render. createdAt `string`\ The date and time the render was created. ## Sample Object [Section titled “Sample Object”](#sample-object) Here’s a sample object of a render: ```json { "id": "ce424057-6b54-41bb-afec-adc35a2b9175", "url": "https://cdn.templated.media/render/ce424057-6b54-41bb-afec-adc35a2b9175.jpg", "width": 1920, "height": 1080, "status": "PENDING", "format": "jpg", "templateId": "1f1231-dasd123-fsdf12312-fds4123-asdas23", "templateName": "Sample Template", "createdAt": "2023-10-02T10:00:00.077Z", } ``` # List all renders > Learn the list all renders of an user using the Templated API. Lists all renders of an user. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all user’s renders: ENDPOINT ```js GET /v1/renders ``` * JavaScript ```js fetch(`https://api.templated.io/v1/renders`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' url = 'https://api.templated.io/v1/renders' headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; public class ListRenders { public static void main(String[] args) { try { String apiKey = "API_KEY"; URL url = new URL("https://api.templated.io/v1/renders"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # Merge renders > Learn to merge renders using the Templated API. Merges multiple renders into a single **PDF**.\ You can also include external PDF URLs to merge with your renders.\ A merge uses 1 API credit. By default, the merged PDF will be returned directly in the response.\ But if you pass the `host` parameter, the merged PDF will be uploaded to our servers and you will receive a URL in the response. ## Parameters [Section titled “Parameters”](#parameters) ids `array` `REQUIRED`\ The render ids of the renders that will be merged. urls `array`\ Optional array of PDF URLs to merge with the renders. The external PDFs will be downloaded and merged after the renders in the order provided. name `string`\ Optional name for the merged PDF file. When `host` is `true`, the hosted URL will include this name. When downloading directly, it will be used as the filename. Defaults to `merged_renders` for downloads. host `boolean`\ If `true`, the merged PDF will be hosted in our servers and you will receive a URL in the response. Defaults to `false`. ## Sample Requests [Section titled “Sample Requests”](#sample-requests) ENDPOINT ```js POST /v1/render/merge ``` ### Merge renders only [Section titled “Merge renders only”](#merge-renders-only) REQUEST ```js fetch("https://api.templated.io/v1/render/merge", { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ "ids": [ "render_id_1", "render_id_2", "render_id_3" ], "name": "my-document", "host": true }) }) .then(response => response.json()) .then(data => { // Handling the response const url = data.url; const link = document.createElement('a'); link.href = url; link.download = 'merged_renders.pdf'; // Trigger the download document.body.appendChild(link); link.click(); }); ``` ### Merge renders with external PDFs [Section titled “Merge renders with external PDFs”](#merge-renders-with-external-pdfs) REQUEST ```js fetch("https://api.templated.io/v1/render/merge", { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ "ids": [ "render_id_1", "render_id_2" ], "urls": [ "https://example.com/document1.pdf", "https://example.com/document2.pdf" ], "host": true }) }) .then(response => response.json()) .then(data => { console.log('Merged PDF URL:', data.url); }); ``` ## Response [Section titled “Response”](#response) The response format depends on the `host` parameter: ### When `host: true` (hosted response) [Section titled “When host: true (hosted response)”](#when-host-true-hosted-response) Returns a JSON object with the URL of the hosted merged PDF: ```json { "url": "https://assets.templated.io/renders/merged/merged-abc123.pdf" } ``` ### When `host: false` (direct download) [Section titled “When host: false (direct download)”](#when-host-false-direct-download) Returns the merged PDF file directly in the response body with the following headers: * Content-Type: `application/pdf` * Content-Disposition: `attachment; filename="merged_renders.pdf"` The PDF file can be downloaded and saved directly from the response. ## Merge Order [Section titled “Merge Order”](#merge-order) The final PDF will contain pages in this order: 1. **Renders**: In the order specified by the `ids` array 2. **External PDFs**: In the order specified by the `urls` array (if provided) For example, if you provide `ids: ["render1", "render2"]` and `urls: ["doc1.pdf", "doc2.pdf"]`, the final PDF will contain: render1 → render2 → doc1.pdf → doc2.pdf # Retrieve a render > Learn to retrieve a render using the Templated API. Retrieves a single Render object referenced by its unique ID. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED` The render id of the render that will be retrieved. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to retrieve a render: ENDPOINT ```js GET /v1/render/:id ``` REQUEST ```js fetch(`https://api.templated.io/v1/render/${id}`, { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` # Add tags to template > Learn how to add tags to an existing template using the Templated API. Add tags to an existing template.\ This endpoint allows you to append new tags to a template without removing existing ones. ## Request Body [Section titled “Request Body”](#request-body) The request body should be an array of strings containing the tags you want to add. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to add tags to a template: ENDPOINT ```js POST /v1/template/{templateId}/tags ``` * JavaScript ```js fetch(`https://api.templated.io/v1/template/${template_id}/tags`, { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify([ "social-media", "instagram", "story" ]) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}/tags' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } tags = [ "social-media", "instagram", "story" ] response = requests.post(url, json=tags, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class AddTemplateTags { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "template_id"; String url = "https://api.templated.io/v1/template/" + templateId + "/tags"; String jsonTags = """ ["social-media", "instagram", "story"] """; URL apiUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonTags.getBytes("utf-8"); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n" . "Content-Type: application/json\r\n", 'method' => 'POST', 'content' => json_encode($tags) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error adding tags"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # Clone a template > Learn how to clone a template using the Templated API. What is a Clone Template? A clone template is a copy of a template that maintains a link to the source template through the `sourceTemplateId` field. Key points about clone templates: * • They maintain a link to the source template through the `sourceTemplateId` field * • Changes to the clone don’t affect the original template * • Clone templates can be tracked and retrieved using the [List template clones](/docs/templates/clones/) endpoint * • They are useful for creating variations of templates while maintaining the source relationship * • Unlike duplicates, clones preserve the relationship to the original template for tracking purposes **Clone templates are not visible in your dashboard.\ They are only accessible through the API.** Creates a clone of an existing template.\ The cloned template will belong to the same user and can be customized independently.\ The clone maintains a reference to the source template through the `sourceTemplateId` field. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The template id of the template that you want to clone. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to clone a template: ENDPOINT ```js POST /v1/template/:id/clone ``` REQUEST ```js fetch(`https://api.templated.io/v1/template/${id}/clone`, { method: 'POST', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns a JSON object with the cloned template details. ```json { "id": "new-template-id-123", "name": "My Template", "width": 1200, "height": 800, "sourceTemplateId": "original-template-id-456", "isClone": true, "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-15T10:30:00Z", } ``` Cloning from a render To create a clone that already includes the layer modifications of a specific render, use the [Create template from render](/docs/templates/create-from-render/) endpoint instead. # List template clones > Learn how to list all clone templates using the Templated API. What is a Clone Template? A clone template is a copy of a template that was created using the [Embed Editor](https://templated.io/embed-image-editor-in-your-app/) with the **`&clone=true`** parameter in the URL.\ Key points about clone templates: * They are created automatically when a user edits a template through the embedded editor with cloning enabled * They maintain a link to the source template through the `sourceTemplateId` field * Changes to the clone don’t affect the original template * Clone templates are not visible in your Templated dashboard * They are only accessible through the API * They are useful for tracking user-specific template variations in your application ## Parameters [Section titled “Parameters”](#parameters) sourceTemplateId `string`\ Filter clones by their source template ID.\ If not provided, returns all clone templates of the account. externalId `string`\ Filter clones by their external ID.\ This is useful for retrieving clones associated with specific records in your system. page `integer`\ The page of the results you would like to retrieve. The initial page is 0. limit `integer`\ The API returns 25 items per page by default but you can request up to 100 using this parameter. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list clone templates: ENDPOINT ```js GET /v1/templates/clones ``` REQUEST ```js fetch('https://api.templated.io/v1/templates/clones?sourceTemplateId=123&page=0&limit=25', { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Count template clones [Section titled “Count template clones”](#count-template-clones) You can also get a count of all clone templates for a given source template ID. Here’s a sample request to count clone templates: ENDPOINT ```js GET /v1/templates/clones/count ``` REQUEST ```js fetch('https://api.templated.io/v1/templates/clones/count?sourceTemplateId=123', { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ### Response [Section titled “Response”](#response) The response will be a JSON object with the count of clone templates. RESPONSE ```js { "count": 100 } ``` # Create template from render > Learn how to create a clone template from an existing render using the Templated API. Creates a clone template from an existing render, with all the render’s layer modifications applied to it.\ The result is a template that matches the render output, which you can then tweak with the [Update template](/docs/templates/update/) endpoint and render again. This is the API equivalent of opening a render in the editor: the source template is cloned and the render’s payload is baked into the clone’s HTML. Iterating on renders programmatically This endpoint is ideal for LLM / agent workflows that refine images step by step: 1. Create a render with the [Create render](/docs/renders/create/) endpoint 2. Create a template from that render with this endpoint 3. Tweak layer positions, texts, or crops with [Update template](/docs/templates/update/) 4. Render the new template The clone keeps a link to the source template through `sourceTemplateId`, does not count toward your plan’s template limit, and is not visible in your dashboard: you can list clones with the [List template clones](/docs/templates/clones/) endpoint. ## Parameters [Section titled “Parameters”](#parameters) renderId `string` `REQUIRED`\ The id of the render that you want to create a template from. ## Behavior notes [Section titled “Behavior notes”](#behavior-notes) * • Pages hidden in the render payload (`hide: true`), and, for multi-page payloads, pages not referenced at all, are removed from the clone, matching what the render produced. * • Render-only options (`format`, `scale`, `transparent`, etc.) are not persisted in the template. * • Renders created before payload storage was introduced return a plain clone of the source template. * • Creating a template from a render is free: it does not consume render credits. * • For multi-page renders, each page produces its own render object but all of them share the same payload. Creating a template from any one page’s render id gives you a clone with ALL the payload’s pages applied, not just that page. ## Sample Request [Section titled “Sample Request”](#sample-request) ENDPOINT ```js POST /v1/template/from-render/:renderId ``` REQUEST ```js fetch(`https://api.templated.io/v1/template/from-render/${renderId}`, { method: 'POST', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns a JSON object with the new template details. ```json { "id": "new-template-id-123", "name": "My Template", "width": 1200, "height": 800, "sourceTemplateId": "original-template-id-456", "isClone": true, "createdAt": "2026-07-17T10:30:00Z", "updatedAt": "2026-07-17T10:30:00Z", } ``` # Create a template > Learn to create a template using the Templated API. This endpoint is used for more complex integrations where you need to create templates programmatically.\ It allows you to create a new template by composing multiple layers into a single design.\ Each layer can be text, images, or shapes, with specific positioning, dimensions, and styling properties. This endpoint allows you to: * Build complex designs by stacking multiple layers * Create multi-page templates (e.g., brochures, presentations, multi-page PDFs) * Position elements precisely using x and y coordinates * Style text with custom fonts, colors, and auto-fitting options * Add images with specific dimensions and positioning * Create shapes using SVG markup for backgrounds, overlays, or decorative elements * Control the visual hierarchy through layer ordering After creating the template, you can open and modify the template in our Editor or use it to generate renders with the [render](/docs/renders/create/) endpoint. ## Parameters [Section titled “Parameters”](#parameters) name `string` `REQUIRED`\ The name of the template. width `number` `REQUIRED`\ The width of the template in pixels (max 5000). height `number` `REQUIRED`\ The height of the template in pixels (max 5000). layers `array`\ An array of layer objects that make up the template. Use this for single-page templates.\ On each layer you must specify the `layer` property, which will be the name identifier of the layer in the template and the layer `type` (image, text, shape). pages `array`\ An array of page objects for multi-page templates. Use this instead of `layers` when you need multiple pages.\ See [Multi-Page Templates](#multi-page-templates) below for details. Note You must provide either `layers` (for single-page templates) or `pages` (for multi-page templates), but not both. duration `number`\ Default video duration in milliseconds for MP4 renders (e.g., `5000` for 5 seconds). When rendering a video without specifying a duration, this value is used as the default. safeZoneWidth `number`\ The width of the print-safe zone in pixels. When set, the Editor displays a margin overlay along the page edges to indicate the area where important content should not be placed (useful for print templates). The overlay is a visual guide only and never appears in renders. For all the available layer properties, see the [Layer Parameters](/docs/renders/create/#layer-parameters) section. ### Grouping Layers [Section titled “Grouping Layers”](#grouping-layers) You can group layers together by setting the same `group` property on multiple layers. Grouped layers are treated as a single unit in the Editor and can be identified programmatically via the API. group `string`\ An optional group name. Layers that share the same `group` value will be wrapped in a group container. The group’s position and dimensions are automatically calculated from the bounding box of its child layers. GROUPED LAYERS EXAMPLE ```json { "layers": [ { "layer": "title", "type": "text", "group": "header", "text": "Hello World", "x": 100, "y": 100, "width": 400, "height": 90 }, { "layer": "logo", "type": "image", "group": "header", "image_url": "https://example.com/logo.png", "x": 100, "y": 220, "width": 200, "height": 200 }, { "layer": "footer", "type": "text", "text": "This layer is not grouped", "x": 100, "y": 900, "width": 500, "height": 50 } ] } ``` In this example, `title` and `logo` are grouped under `"header"`, while `footer` remains independent. ## Multi-Page Templates [Section titled “Multi-Page Templates”](#multi-page-templates) You can create templates with multiple pages by using the `pages` field instead of `layers`. Each page is an object with its own set of layers and optional dimension overrides. ### Page Parameters [Section titled “Page Parameters”](#page-parameters) page `string` `REQUIRED`\ A unique identifier for the page (e.g., `"page-1"`, `"cover"`, `"back"`). layers `object` `REQUIRED`\ An object containing the layers for this page. Each key is the layer name and the value is a layer object with its properties (`type`, `text`, `x`, `y`, etc.). width `number`\ Optional width override for this page in pixels. If not provided, the template-level `width` is used. height `number`\ Optional height override for this page in pixels. If not provided, the template-level `height` is used. Tip Each page can have different dimensions, allowing you to create templates with mixed page sizes (e.g., a landscape cover page and portrait content pages). MULTI-PAGE EXAMPLE ```json { "name": "Product Brochure", "width": 1080, "height": 1080, "pages": [ { "page": "cover", "layers": { "background": { "type": "image", "x": 0, "y": 0, "width": 1080, "height": 1080, "image_url": "https://example.com/cover-bg.jpg" }, "title": { "type": "text", "x": 100, "y": 400, "width": 880, "height": 200, "text": "Product Brochure", "color": "#ffffff", "font_size": "64px", "font_family": "Inter" } } }, { "page": "details", "layers": { "heading": { "type": "text", "x": 80, "y": 60, "width": 920, "height": 80, "text": "Key Features", "color": "#333333", "font_size": "48px" }, "body": { "type": "text", "x": 80, "y": 180, "width": 920, "height": 600, "text": "Feature descriptions go here...", "color": "#666666", "font_size": "24px" } } } ] } ``` After creating a multi-page template, you can retrieve its pages using the [List Template Pages](/docs/templates/pages/) endpoint. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to create a single-page template: ENDPOINT ```js POST /v1/template ``` REQUEST ```js fetch('https://api.templated.io/v1/template', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "name": "Summer Music Festival Post", "width": 1200, "height": 630, "layers": [ { "layer": "background-image", "type": "image", "width": 1200, "height": 630, "x": 0, "y": 0, "image_url": "https://images.unsplash.com/photo-1533174072545-7a4b6ad7a6c3" }, { "layer": "event-name", "type": "text", "width": 1000, "height": 120, "x": 100, "y": 80, "text": "SUMMER BEATS\nFESTIVAL 2024", "color": "#ffffff", "font_family": "ArchivoBlack-Regularttf", "font_size": "72px", "autofit": "height" }, { "layer": "details-box", "type": "shape", "width": 800, "height": 180, "x": 330, "y": 240, "html": "" } ] }) }) ``` # Delete a template > Learn how to delete a template using the Templated API. Delete a specific template by its ID. Caution This action is irreversible. Once a template is deleted, it cannot be recovered.\ Be sure you want to delete the template before proceeding. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to delete a template: ENDPOINT ```js DELETE /v1/template/{id} ``` * JavaScript ```js fetch(`https://api.templated.io/v1/template/${TEMPLATE_ID}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => { if (response.status === 204) { console.log('Template deleted successfully'); } }) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'TEMPLATE_ID' url = f'https://api.templated.io/v1/template/{template_id}' headers = {'Authorization': f'Bearer {api_key}'} response = requests.delete(url, headers=headers) if response.status_code == 204: print('Template deleted successfully') else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; public class DeleteRender { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "TEMPLATE_ID"; URL url = new URL("https://api.templated.io/v1/template/" + templateId); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("DELETE"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_NO_CONTENT) { System.out.println("Template deleted successfully"); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = @file_get_contents($url, false, $context); if ($http_response_header[0] == 'HTTP/1.1 204 No Content') { echo "Template deleted successfully"; } else { echo "Error deleting template"; } ?> ``` ## Response [Section titled “Response”](#response) A successful deletion will return a `204 No Content` response with no body. ### Error Responses [Section titled “Error Responses”](#error-responses) | Status Code | Description | | ----------- | ------------------------------------------------------------- | | 401 | Not authorized - Invalid or missing API key | | 403 | Forbidden - You don’t have permission to delete this template | | 404 | Not Found - Template or user not found | | 500 | Internal Server Error - An unexpected error occurred | # Duplicate a template > Learn how to duplicate a template using the Templated API. Creates a duplicate of an existing template.\ The duplicated template will belong to the same user and can be customized independently.\ Duplicating a template counts towards the template limit of your plan. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The template id of the template that you want to duplicate. name `string` `OPTIONAL`\ The name for the duplicated template.\ If not provided, defaults to “Copy of {original\_template\_name}”. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to duplicate a template: ENDPOINT ```js POST /v1/template/:id/duplicate ``` REQUEST WITH CUSTOM NAME ```js fetch(`https://api.templated.io/v1/template/${id}/duplicate?name=My Custom Template`, { method: 'POST', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` REQUEST WITH DEFAULT NAME ```js fetch(`https://api.templated.io/v1/template/${id}/duplicate`, { method: 'POST', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns a JSON object with the duplicated template details. ```json { "id": "new-template-id-123", "name": "My Custom Template", "width": 1200, "height": 800, "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-15T10:30:00Z", } ``` # List gallery templates > Retrieve all templates from the Templated gallery using the API. Lists all templates available in the public [Template Gallery](https://templated.io/templates/).\ Gallery templates are professionally designed templates that you can use as a starting point for your projects\*\*.\*\* Browse the Gallery You can explore all available templates visually in our [Template Gallery](https://templated.io/templates/) before using the API. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------------- | ------- | ------- | ------------------------------------------ | | `query` | string | - | Filter templates by name or description | | `category` | string | - | Filter templates by category name | | `tags` | string | - | Filter templates by tags (comma-separated) | | `page` | integer | 0 | Page number for pagination | | `limit` | integer | 25 | Number of results per page | | `width` | integer | - | Filter templates by exact width | | `height` | integer | - | Filter templates by exact height | | `includeLayers` | boolean | false | Include template layers in response | ## Response [Section titled “Response”](#response) Returns an array of template objects. Each template includes the following notable fields: | Field | Type | Description | | ------------- | ------- | -------------------------------------------------------- | | `id` | string | Unique identifier of the template | | `name` | string | Name of the template | | `description` | string | Description of the template | | `width` | integer | Width of the template in pixels | | `height` | integer | Height of the template in pixels | | `thumbnail` | string | URL of the template thumbnail image | | `category` | object | Category information (name, description) | | `tags` | array | List of tags associated with the template | | `background` | string | The background color of the template | | `layers` | array | List of template layers (only when `includeLayers=true`) | ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all gallery templates: ENDPOINT ```js GET /v1/templates/gallery ``` * JavaScript ```js fetch('https://api.templated.io/v1/templates/gallery', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' url = 'https://api.templated.io/v1/templates/gallery' headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` ## Filtering Examples [Section titled “Filtering Examples”](#filtering-examples) ### Filter by Category [Section titled “Filter by Category”](#filter-by-category) ```js fetch('https://api.templated.io/v1/templates/gallery?category=Certificate', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Filter by Dimensions [Section titled “Filter by Dimensions”](#filter-by-dimensions) ```js // Get Instagram post templates (1080x1080) fetch('https://api.templated.io/v1/templates/gallery?width=1080&height=1080', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Search by Name [Section titled “Search by Name”](#search-by-name) ```js fetch('https://api.templated.io/v1/templates/gallery?query=certificate', { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) ``` ### Opening a Gallery Template in the Editor [Section titled “Opening a Gallery Template in the Editor”](#opening-a-gallery-template-in-the-editor) You can launch the Templated editor with a gallery template pre-loaded using the `gallery` URL parameter: ```plaintext https://app.templated.io/editor?gallery={galleryTemplateId} ``` This will automatically create a copy of the gallery template in the user’s account and open it for editing. For embedded editor integrations, you can use: ```plaintext https://app.templated.io/editor?embed={embedConfigId}&gallery={galleryTemplateId} ``` Note Gallery templates are read-only. When you open a gallery template in the editor or clone it via API, a copy is automatically created in your account that you can customize. # The template object > Learn the properties of a template object in the Templated API. These attributes define the properties of a template.\ The template object is used to store template data, including dimensions, user information, and category details. ## Attributes [Section titled “Attributes”](#attributes) id `string`\ The unique UUID for the template. name `string`\ The name of the template. description `string`\ A brief description of the template. width `integer`\ The width of the template in pixels. height `integer`\ The height of the template in pixels. thumbnail `string`\ URL of the template’s thumbnail image. layersCount `integer`\ The number of layers (not locked) of the template. user `User object`\ The user who created or owns the template. folderId `string`\ The folder ID of folder the template belongs to. ## Sample Object [Section titled “Sample Object”](#sample-object) Here’s a sample object of a template: ```json { "id": "306c724a-d138-486a-a601-0b2a9ced52be", "name": "Twitter Bubble Square Template", "description": "This is a sample template for demonstration.", "width": 1024, "height": 1024, "thumbnail": "https://templated-assets.s3.us-east-1.amazonaws.com/public/thumbnail/306c724a-d138-486a-a601-0b2a9ced52be.webp", "user": { "id": "872s0atn-l4o5-09g9-gth2-oy7f79df6tuw", "name": "Mark Doe" } } ``` # List template layers > Learn the list all layers of a template using the Templated API. Lists all layers of a template.\ By default, locked layers are not returned. Set `includeLockedLayers=true` to include them. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The template id of the template that you want to retrieve the layers. includeLockedLayers `boolean`\ Defaults to `false`. When `true`, returns layers even if they are marked as locked in the template. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all layers of a template: ENDPOINT ```js GET /v1/template/:id/layers ``` ENDPOINT (Include locked layers) ```js GET /v1/template/:id/layers?includeLockedLayers=true ``` REQUEST ```js fetch(`https://api.templated.io/v1/template/${id}/layers`, { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns an array of JSON objects with the layer details. ```json [ { "layer": "text-1", "type": "text", "description": "", "group": "header" }, { "layer": "image-1", "type": "image", "description": "Profile image layer", "group": "header" }, { "layer": "footer", "type": "text", "description": "" } ... ] ``` Each layer object contains the following properties: layer `string`\ The unique identifier of the layer. type `string`\ The type of layer (e.g., “text”, “image”, “shape”, etc.). description `string`\ Optional description of the layer.\ The description can be added in the Editor. group `string`\ The name of the group this layer belongs to.\ Layers that share the same `group` value are grouped together in the Editor.\ This property is only present for layers that belong to a group. # List all templates > Learn the list all templates of an user using the Templated API. Lists all templates of an user.\ You can filter and customize the results using various query parameters. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------------- | ------- | ------- | --------------------------------------------- | | `query` | string | - | Filter templates by name | | `page` | integer | 0 | Page number for pagination | | `limit` | integer | 25 | Number of results per page | | `width` | integer | - | Filter templates by width | | `height` | integer | - | Filter templates by height | | `tags` | string | - | Filter templates by tags (comma-separated) | | `externalId` | string | - | Filter templates by external ID | | `includeLayers` | boolean | false | Include template layers in response | | `includePages` | boolean | false | Include template pages and layers in response | ## Response [Section titled “Response”](#response) Each template in the response includes the following notable fields: | Field | Type | Description | | ------------ | ------ | --------------------------------------------------------------------------------- | | `background` | string | The background color of the template (e.g., `#ffffff` or `rgb(255, 255, 255)`) | | `layers` | array | List of template layers (only included when `includeLayers=true`) | | `pages` | array | List of template pages with their layers (only included when `includePages=true`) | ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all user’s templates: ENDPOINT ```js GET /v1/templates ``` * JavaScript ```js fetch(`https://api.templated.io/v1/templates`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` }, // Example with all query parameters params: { query: 'Template Name', page: 0, limit: 25, width: 1920, height: 1080, tags: 'tag1,tag2', externalId: 'my-external-id', includeLayers: true } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' url = 'https://api.templated.io/v1/templates' # Example with all query parameters params = { 'query': 'Template Name', 'page': 0, 'limit': 25, 'width': 1920, 'height': 1080, 'externalId': 'my-external-id', 'includeLayers': True } headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, params=params, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; public class ListTemplates { public static void main(String[] args) { try { String apiKey = "API_KEY"; // Example with all query parameters String queryParams = String.format("?query=%s&page=%d&limit=%d&width=%d&height=%d&externalId=%s&includeLayers=%b", URLEncoder.encode("Template Name", "UTF-8"), 0, 25, 1920, 1080, URLEncoder.encode("my-external-id", "UTF-8"), true ); URL url = new URL("https://api.templated.io/v1/templates" + queryParams); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php 'Template Name', 'page' => 0, 'limit' => 25, 'width' => 1920, 'height' => 1080, 'externalId' => 'my-external-id', 'includeLayers' => 'true' ); $url = "https://api.templated.io/v1/templates?" . http_build_query($params); $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # List template pages > Learn to list all pages of a template using the Templated API. Lists all pages of a template.\ This endpoint returns all pages defined in a multi-page template.\ By default, locked layers are not returned. Set `includeLockedLayers=true` to include them. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The template id of the template that you want to retrieve the pages. includeLockedLayers `boolean`\ Defaults to `false`. When `true`, returns layers even if they are marked as locked in the template. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all pages of a template: ENDPOINT ```js GET /v1/template/:id/pages ``` ENDPOINT (Include locked layers) ```js GET /v1/template/:id/pages?includeLockedLayers=true ``` REQUEST ```js fetch(`https://api.templated.io/v1/template/${id}/pages`, { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Response [Section titled “Response”](#response) The API returns an array of JSON objects with the page details. ```json [ { "page": "page-1", "layers": { "text-1": { "layer": "text-1", "type": "text", "description": "Title text", "group": "header" }, "image-1": { "layer": "image-1", "type": "image", "description": "Cover image", "group": "header" }, "footer": { "layer": "footer", "type": "text", "description": "Footer text" } } }, { "page": "page-2", "layers": { "text-2": { "layer": "text-2", "type": "text", "description": "Body text" } } } ... ] ``` Each page object contains the following properties: page `string`\ The unique identifier of the page. layers `object`\ An object containing all layers within this page, where each key is the layer ID and the value is the layer object with its properties (layer, type, description, group, etc.). # Remove tags from template > Learn how to remove tags from an existing template using the Templated API. Remove tags from an existing template.\ This endpoint allows you to remove specific tags from a template. ## Request Body [Section titled “Request Body”](#request-body) The request body should be an array of strings containing the tags you want to remove. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to remove tags from a template: ```plaintext DELETE /v1/template/{templateId}/tags ``` * JavaScript ```js fetch(`https://api.templated.io/v1/template/${template_id}/tags`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify([ "social-media", "instagram" ]) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}/tags' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } tags = [ "social-media", "instagram" ] response = requests.delete(url, json=tags, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class RemoveTemplateTags { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "template_id"; String url = "https://api.templated.io/v1/template/" + templateId + "/tags"; String jsonTags = """ ["social-media", "instagram"] """; URL apiUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection(); connection.setRequestMethod("DELETE"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonTags.getBytes("utf-8"); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n" . "Content-Type: application/json\r\n", 'method' => 'DELETE', 'content' => json_encode($tags) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error removing tags"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # List template renders > Learn the list all renders of a template using the Templated API. Lists all renders of a template. ## Parameters [Section titled “Parameters”](#parameters) id `string` `REQUIRED`\ The template id that you want to retrieve the renders. page `integer`\ The page of the results you would like to retrieve. The initial page is 0. limit `integer`\ The API returns 25 items per page by default but you can request up to 100 using this parameter. externalId `string`\ Filter renders by external ID. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all renders of a template: ENDPOINT ```js GET /v1/template/:id/renders ``` REQUEST ```js fetch(`https://api.templated.io/v1/template/${id}/renders?page=2&limit=50&externalId=my-external-id`, { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` # Retrieve a template > Learn to retrieve a template using the Templated API. Retrieves a single Template object referenced by its unique ID. ## Path Parameters [Section titled “Path Parameters”](#path-parameters) id `string` `REQUIRED`\ The template id of the template that will be retrieved. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Default | Description | | --------------- | ------- | ------- | --------------------------------------------- | | `includeLayers` | boolean | false | Include template layers in response | | `includePages` | boolean | false | Include template pages and layers in response | ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to retrieve a template: ENDPOINT ```js GET /v1/template/:id ``` * JavaScript ```js fetch(`https://api.templated.io/v1/template/${id}?includeLayers=true`, { method: 'GET', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' params = { 'includeLayers': True } headers = {'Authorization': f'Bearer {api_key}'} response = requests.get(url, params=params, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * PHP ```php 'true' ); $url = "https://api.templated.io/v1/template/{$templateId}?" . http_build_query($params); $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error fetching data"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # Update tags for template > Learn how to update tags for an existing template using the Templated API. Update tags for an existing template.\ This endpoint allows you to replace all existing tags of a template with a new set of tags. ## Request Body [Section titled “Request Body”](#request-body) The request body should be an array of strings containing the new tags you want to set. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to update tags for a template: ```plaintext PUT /v1/template/{templateId}/tags ``` * JavaScript ```js fetch(`https://api.templated.io/v1/template/${template_id}/tags`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify([ "new-tag1", "new-tag2", "new-tag3" ]) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}/tags' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } tags = [ "new-tag1", "new-tag2", "new-tag3" ] response = requests.put(url, json=tags, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class UpdateTemplateTags { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "template_id"; String url = "https://api.templated.io/v1/template/" + templateId + "/tags"; String jsonTags = """ ["new-tag1", "new-tag2", "new-tag3"] """; URL apiUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection(); connection.setRequestMethod("PUT"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonTags.getBytes("utf-8"); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ 'header' => "Authorization: Bearer {$apiKey}\r\n" . "Content-Type: application/json\r\n", 'method' => 'PUT', 'content' => json_encode($tags) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error updating tags"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` # Update a template > Learn to update a template using the Templated API. This endpoint allows you to update an existing template by modifying its layers, properties, or content.\ You can update specific layers without affecting the rest of the template, making it efficient for partial updates. Key features: * Update only the layers/pages you need to change * Modify template properties like name, dimensions, and descriptions * Add new layers to existing pages * Update text, images, shapes, and other layer properties * Unchanged layers and pages remain intact After updating the template, the changes will be reflected in the Editor and any future renders created from this template. ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) id `string` `REQUIRED`\ The template ID of the template you want to update (passed in the URL path). ### Query Parameters [Section titled “Query Parameters”](#query-parameters) replaceLayers `boolean` `OPTIONAL`\ When set to `true`, layers not included in the request will be **removed** from the template.\ Default is `false` (partial update mode - existing layers not in the request remain unchanged).\ Use this when you want to completely replace the template’s layers rather than just updating specific ones. ### Body Parameters [Section titled “Body Parameters”](#body-parameters) name `string` `OPTIONAL`\ The name of the template. width `number` `OPTIONAL`\ The width of the template in pixels (max 5000). height `number` `OPTIONAL`\ The height of the template in pixels (max 5000). description `string` `OPTIONAL`\ A description of the template. externalId `string` `OPTIONAL`\ An external identifier you can attach to the template to associate it with a record in your own system (e.g., one of your end-users).\ Useful when offering per-user templates through your service.\ You can later filter templates by this value via the [List templates](/docs/templates/list/) endpoint using the `externalId` query parameter. safeZoneWidth `number` `OPTIONAL`\ The width of the print-safe zone in pixels. When set, the Editor displays a margin overlay along the page edges to indicate the area where important content should not be placed (useful for print templates).\ The overlay is a visual guide only and never appears in renders. Set it to `0` to remove the safe zone. layers `array` `OPTIONAL`\ An array of layer objects to update.\ Only include the layers you want to modify or add.\ Each layer must specify the `layer` property (layer name identifier) and the layer `type` (image, text, shape). pages `array` `OPTIONAL`\ For multi-page templates, an array of page objects containing the layers to update.\ Only include the pages and layers you want to modify. hide `boolean` `OPTIONAL`\ A page-level property inside an entry of the `pages` array. When `true`, the page is REMOVED from the template. This is destructive: the page and its layers are deleted from the template HTML and cannot be restored by a later update with `hide: false`.\ (In render payloads, `hide` only skips rendering the page and does not modify the template.) For all the available layer properties, see the [Layer Parameters](/docs/renders/create/#layer-parameters) section. ### Grouping Layers [Section titled “Grouping Layers”](#grouping-layers) You can group layers by setting the same `group` property on multiple layers. See [Create a template - Grouping Layers](/docs/templates/create/#grouping-layers) for details. When adding new grouped layers to an existing template: * If a group with that name already exists, the new layers are added to it. * If the group doesn’t exist, it is created automatically with its position and dimensions calculated from the bounding box of the layers. ## Sample Requests [Section titled “Sample Requests”](#sample-requests) ### Update specific layers in a template [Section titled “Update specific layers in a template”](#update-specific-layers-in-a-template) Here’s a sample request to update only specific layers: ENDPOINT ```js PUT /v1/template/{id} ``` * JavaScript UPDATE SPECIFIC LAYERS ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "layers": [ { "layer": "event-name", "type": "text", "text": "UPDATED EVENT NAME", "color": "#ff0000" }, { "layer": "background-image", "type": "image", "image_url": "https://images.unsplash.com/photo-new-image-id" } ] }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "layers": [ { "layer": "event-name", "type": "text", "text": "UPDATED EVENT NAME", "color": "#ff0000" }, { "layer": "background-image", "type": "image", "image_url": "https://images.unsplash.com/photo-new-image-id" } ] } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class UpdateTemplate { public static void main(String[] args) { try { String apiKey = "API_KEY"; String templateId = "template_id"; String url = "https://api.templated.io/v1/template/" + templateId; String jsonData = """ { "layers": [ { "layer": "event-name", "type": "text", "text": "UPDATED EVENT NAME", "color": "#ff0000" }, { "layer": "background-image", "type": "image", "image_url": "https://images.unsplash.com/photo-new-image-id" } ] } """; URL apiUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection(); connection.setRequestMethod("PUT"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonData.getBytes("utf-8"); os.write(input, 0, input.length); } int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php [ [ "layer" => "event-name", "type" => "text", "text" => "UPDATED EVENT NAME", "color" => "#ff0000" ], [ "layer" => "background-image", "type" => "image", "image_url" => "https://images.unsplash.com/photo-new-image-id" ] ] ]; $url = "https://api.templated.io/v1/template/{$templateId}"; $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n" . "Content-Type: application/json\r\n", 'method' => 'PUT', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === FALSE) { echo "Error updating template"; } else { $data = json_decode($result, true); print_r($data); } ?> ``` ### Update autofit font limits and lock state [Section titled “Update autofit font limits and lock state”](#update-autofit-font-limits-and-lock-state) Here’s a sample request that removes the minimum autofit font size of a text layer and unlocks another layer, making it flexible: ENDPOINT ```js PUT /v1/template/{id} ``` * JavaScript UPDATE FONT LIMITS AND LOCK STATE ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "layers": [ { "layer": "title", "type": "text", "min_font_size": 0 }, { "layer": "footer", "type": "text", "locked": false } ] }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "layers": [ { "layer": "title", "type": "text", "min_font_size": 0 }, { "layer": "footer", "type": "text", "locked": False } ] } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ### Update template properties and layers [Section titled “Update template properties and layers”](#update-template-properties-and-layers) You can also update template metadata along with layers: * JavaScript UPDATE PROPERTIES AND LAYERS ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "name": "Updated Template Name", "description": "This template has been updated", "width": 1920, "height": 1080, "layers": [ { "layer": "title", "type": "text", "text": "New Title Text", "font_size": "64px", "color": "#ffffff" } ] }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "name": "Updated Template Name", "description": "This template has been updated", "width": 1920, "height": 1080, "layers": [ { "layer": "title", "type": "text", "text": "New Title Text", "font_size": "64px", "color": "#ffffff" } ] } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ### Update multi-page template [Section titled “Update multi-page template”](#update-multi-page-template) For multi-page templates, use the `pages` array: * JavaScript UPDATE MULTI-PAGE TEMPLATE ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "pages": [ { "page": "page-1", "layers": { "title": { "layer": "title", "type": "text", "text": "Updated Page 1 Title" } } }, { "page": "page-2", "layers": { "subtitle": { "layer": "subtitle", "type": "text", "text": "Updated Page 2 Subtitle" } } } ] }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "pages": [ { "page": "page-1", "layers": { "title": { "layer": "title", "type": "text", "text": "Updated Page 1 Title" } } }, { "page": "page-2", "layers": { "subtitle": { "layer": "subtitle", "type": "text", "text": "Updated Page 2 Subtitle" } } } ] } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ### Assign a template to one of your end-users [Section titled “Assign a template to one of your end-users”](#assign-a-template-to-one-of-your-end-users) If you’re building a service on top of Templated and want to associate a template (for example, a clone) with one of your own users, set the `externalId` field.\ You can then list and filter templates per end-user via the [List templates](/docs/templates/list/) endpoint. * JavaScript ASSIGN EXTERNAL ID ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "externalId": "your-user-id" }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "externalId": "your-user-id" } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ### Set the print-safe zone of a template [Section titled “Set the print-safe zone of a template”](#set-the-print-safe-zone-of-a-template) For print templates, set `safeZoneWidth` to display a margin overlay in the Editor indicating the area where important content should not be placed. Set it to `0` to remove the safe zone. * JavaScript SET PRINT-SAFE ZONE ```js fetch(`https://api.templated.io/v1/template/${template_id}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "safeZoneWidth": 50 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' url = f'https://api.templated.io/v1/template/{template_id}' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } data = { "safeZoneWidth": 50 } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ### Replace all layers in a template [Section titled “Replace all layers in a template”](#replace-all-layers-in-a-template) Use `replaceLayers=true` when you want to completely replace the template’s layers. Any layers not included in your request will be removed: ENDPOINT ```js PUT /v1/template/{id}?replaceLayers=true ``` * JavaScript REPLACE ALL LAYERS ```js // This will replace ALL layers in the template with only the layers specified below // Any existing layers not in this array will be REMOVED fetch(`https://api.templated.io/v1/template/${template_id}?replaceLayers=true`, { method: 'PUT', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ "layers": [ { "layer": "new-title", "type": "text", "text": "My New Title", "x": 100, "y": 100, "width": 400, "height": 50, "font_size": "48px", "color": "#000000" }, { "layer": "new-image", "type": "image", "image_url": "https://images.unsplash.com/photo-example", "x": 100, "y": 200, "width": 400, "height": 300 } ] }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' template_id = 'template_id' # Add ?replaceLayers=true to remove layers not in the request url = f'https://api.templated.io/v1/template/{template_id}?replaceLayers=true' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } # This will replace ALL layers - any existing layers not listed here will be removed data = { "layers": [ { "layer": "new-title", "type": "text", "text": "My New Title", "x": 100, "y": 100, "width": 400, "height": 50, "font_size": "48px", "color": "#000000" }, { "layer": "new-image", "type": "image", "image_url": "https://images.unsplash.com/photo-example", "x": 100, "y": 200, "width": 400, "height": 300 } ] } response = requests.put(url, json=data, headers=headers) if response.status_code == 200: print(response.json()) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` ## Response [Section titled “Response”](#response) The API returns a JSON object with the updated template details: ```json { "id": "template-id-123", "name": "Updated Template Name", "description": "This template has been updated", "width": 1920, "height": 1080, "layersCount": 15, "pagesCount": 1, "safeZoneWidth": 50, "updatedAt": "2024-01-15T10:30:00Z", "createdAt": "2024-01-01T08:00:00Z" } ``` ## Error Responses [Section titled “Error Responses”](#error-responses) | Status Code | Description | | ----------- | ----------------------------------------------------------------------------------- | | 401 | Not authorized - Invalid or missing API key | | 403 | Forbidden - You don’t have permission to update this template or account is blocked | | 404 | Not Found - Template not found | | 500 | Internal Server Error - An unexpected error occurred | ## Important Notes [Section titled “Important Notes”](#important-notes) Partial vs Full Update By default, this endpoint performs **partial updates** - only the layers you include in the request are modified, and all other layers remain unchanged. If you want to **replace all layers** (removing any layers not in your request), add `?replaceLayers=true` to the URL: ```plaintext PUT /v1/template/{id}?replaceLayers=true ``` Layer Identification Layers are identified by their `layer` name property.\ If a layer with the specified name exists, it will be updated.\ If it doesn’t exist, a new layer will be created. Using replaceLayers When using `replaceLayers=true`, any layers **not included** in your request will be permanently removed from the template.\ Make sure to include all layers you want to keep when using this option. # Upload an image > Learn to upload an image using the Templated API. Upload an image to your account. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to upload an image: ENDPOINT ```js POST /v1/upload Content-Type: multipart/form-data ``` ```js // Create form data const fileInput = document.getElementById('fileInput'); const formData = new FormData(); formData.append('file', fileInput.files[0]); // Optional: add tags to organize your uploads formData.append('tags', 'product'); formData.append('tags', 'featured'); // Optional: add an external ID to link with your own system formData.append('externalId', 'your-external-reference-id'); fetch('https://api.templated.io/v1/upload', { method: 'POST', body: formData, headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Parameters [Section titled “Parameters”](#parameters) | Parameter | Type | Required | Description | | ------------ | --------- | -------- | --------------------------------------------------------------------------------- | | `file` | File | Yes | The image file to upload (JPG, PNG, WebP, or SVG). Maximum size: 2MB | | `tags` | String\[] | No | Optional tags to organize your uploads. Can be provided multiple times | | `externalId` | String | No | Optional external reference ID to link the upload with records in your own system | # Delete uploads > Learn how to delete one or multiple uploads using the Templated API. Delete one or multiple uploads by their IDs. All specified uploads must exist and belong to your account for the deletion to proceed. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to delete uploads: ENDPOINT ```js DELETE /v1/uploads?ids=UPLOAD_ID_1&ids=UPLOAD_ID_2 ``` * JavaScript ```js // Delete single upload fetch(`https://api.templated.io/v1/uploads?ids=${UPLOAD_ID_1}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log('Response:', data)) .catch(error => console.error('Error:', error)); // Delete multiple uploads const uploadIds = [UPLOAD_ID_1, UPLOAD_ID_2]; const params = uploadIds.map(id => `ids=${id}`).join('&'); fetch(`https://api.templated.io/v1/uploads?${params}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${API_KEY}` } }) .then(response => response.json()) .then(data => console.log('Response:', data)) .catch(error => console.error('Error:', error)); ``` * Python ```python import requests api_key = 'API_KEY' upload_ids = ['UPLOAD_ID_1', 'UPLOAD_ID_2'] # Prepare query parameters params = {'ids': upload_ids} url = 'https://api.templated.io/v1/uploads' headers = {'Authorization': f'Bearer {api_key}'} response = requests.delete(url, headers=headers, params=params) if response.status_code == 200: result = response.json() print(f"Successfully deleted: {result['deleted']}") print(result['message']) else: print('Request failed. Response code:', response.status_code) print(response.text) ``` * Java ```java import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.io.BufferedReader; import java.io.InputStreamReader; public class DeleteUploads { public static void main(String[] args) { try { String apiKey = "API_KEY"; String[] uploadIds = {"UPLOAD_ID_1", "UPLOAD_ID_2"}; // Build query parameters StringBuilder params = new StringBuilder(); for (int i = 0; i < uploadIds.length; i++) { if (i > 0) params.append("&"); params.append("ids=").append(URLEncoder.encode(uploadIds[i], "UTF-8")); } URL url = new URL("https://api.templated.io/v1/uploads?" + params.toString()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("DELETE"); connection.setRequestProperty("Authorization", "Bearer " + apiKey); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String response = reader.readLine(); System.out.println("Response: " + response); } else { System.out.println("Request failed. Response Code: " + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` * PHP ```php $uploadIds]); $url = "https://api.templated.io/v1/uploads?{$params}"; $options = [ 'http' => [ 'header' => "Authorization: Bearer {$apiKey}\r\n", 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result !== false) { $response = json_decode($result, true); echo "Successfully deleted: " . implode(', ', $response['deleted']) . "\n"; echo $response['message'] . "\n"; } else { echo "Error deleting uploads\n"; } ?> ``` ## Response [Section titled “Response”](#response) ### Success Response [Section titled “Success Response”](#success-response) A successful deletion will return a `200 OK` response with details about the deleted uploads: ```json { "deleted": ["upload-id-1", "upload-id-2"], "message": "Successfully deleted 2 upload(s)" } ``` ### Error Responses [Section titled “Error Responses”](#error-responses) | Status Code | Description | Response Body | | ----------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 400 | Bad Request - Invalid upload IDs or permission issues | `{"not_found": ["id1"], "unauthorized": ["id2"], "error": "Cannot delete uploads: some uploads were not found or you don't have permission to delete them"}` | | 400 | Bad Request - No upload IDs provided | `{"error": "At least one upload ID must be provided"}` | | 401 | Not authorized - Invalid or missing API key | `{"error": "Not authorized"}` | | 404 | Not Found - User not found | `{"error": "User not found"}` | | 500 | Internal Server Error - An unexpected error occurred | `{"error": "An unexpected error occurred"}` | ## Important Notes [Section titled “Important Notes”](#important-notes) * **Atomic Operation**: Either all specified uploads are deleted, or none are deleted. If any upload ID is invalid or unauthorized, the entire operation fails. * **Bulk Support**: You can delete multiple uploads in a single request by passing multiple `ids` parameters. ## Query Parameters [Section titled “Query Parameters”](#query-parameters) | Parameter | Type | Required | Description | | --------- | --------- | -------- | ----------------------------------------------------------------------------------- | | `ids` | string\[] | Yes | One or more upload IDs to delete. Pass multiple `ids` parameters for bulk deletion. | # The upload object > Learn the properties of an upload object in the Templated API. These attributes define the properties of an upload object.\ The upload object is used to store images in an organized way. ## Attributes [Section titled “Attributes”](#attributes) id `string`\ The unique UUID for the upload. name `string`\ The file name of the upload. size `number`\ The size of the upload in bytes. contentType `string`\ The content type of the upload. createdAt `string`\ The date and time when the upload was created. ## Sample Object [Section titled “Sample Object”](#sample-object) Here’s a sample object of an upload: ```json { "id": "3c435c83-6682-4468-939f-6af175caacex", "name": "my-image.jpg", "size": 123456, "contentType": "image/jpeg", "createdAt": "2024-01-01T00:00:00Z" } ``` # List all uploads > Learn the list all uploads of an user using the Templated API. Lists all uploads of an user. ## Sample Request [Section titled “Sample Request”](#sample-request) Here’s a sample request to list all user’s uploads: ENDPOINT ```js GET /v1/uploads ``` REQUEST ```js fetch('https://api.templated.io/v1/uploads?query=banner&tags=social,marketing&page=0&limit=10', { method: 'GET', headers: { 'Authorization' : `Bearer ${API_KEY}` } }) ``` ## Parameters [Section titled “Parameters”](#parameters) query `string`\ Search uploads by name or tag. tags `string[]`\ Filter uploads by tags (comma-separated). page `integer`\ Page number for pagination. Default is `0`. limit `integer`\ Number of items per page. Default is `15`.