HTML postcard designer API

Design once. Export HTML. Send anywhere.

Mount the HTML postcard designer with one tag, get front and back HTML back with merge variables when your user saves, and forward it to Lob, PostGrid or your own renderer. Sandbox keys are free and never expire.

One web component Any framework, or none Front and back HTML Domain-locked API keys

Last updated

<postcard-designer
  id="designer"
  api-key="YOUR_API_KEY"
  config='{"size":{"w":6,"h":4},"htmlButtonBehaviour":"save","user_id":"user-123"}'
></postcard-designer>

<script type="module">
  import { register } from 'https://cdn.jsdelivr.net/npm/designertool-cdn-loader/+esm';
  await register();

  const designer = document.getElementById('designer');

  // Fires when the user saves: one HTML document per side
  designer.addEventListener('html-button-click', (event) => {
    const { front, back } = event.detail[0];
    saveDesign(front.HTMLContent, back?.HTMLContent);
  });

  designer.addEventListener('exit', () => closeEditor());
</script>
Embed guide

Live in three steps

Most teams have the editor rendering inside their app in under an hour, and exporting to their mail provider the same day.

  1. 1

    Create a project and API key

    In the portal, create a project, generate an API key and add the domains the editor will run on. Requests are only accepted from those domains, so the key is safe to use in the browser.

  2. 2

    Add the element

    Load designertool-cdn-loader from the CDN or npm, call register(), and place <postcard-designer> with your api-key and a config. Pass a user_id per end user to keep their uploads separate.

  3. 3

    Handle the save

    Set htmlButtonBehaviour to "save" and listen for html-button-click. The event carries the front and back HTML; forward it to Lob, PostGrid or your own renderer.

Save payload

What the save event returns

One object per side. HTMLContent is a self-contained HTML document with inline styles and font links, sized with bleed. currentState is the design as JSON, if you want to keep it alongside the HTML.

  • Sizes: 4×6, 6×9 and 6×11 postcards and 8.5×11 letters. The canvas adds 0.25 in of bleed
  • Merge variables are written as {{merge_tag}}, the syntax Lob merge variables and PostGrid mergeVariables both read
  • The address block is left clear on the back. Letters return a front only, so back is null
  • Reopen a design by passing its HTML back as initial_html in the config (a string or a URL)
event.detail[0]
{
  "front": {
    "HTMLContent": "<html><head>…</head><body>… {{first_name}} …</body></html>",
    "currentState": { "items": [ … ] }
  },
  "back": {
    "HTMLContent": "<html><head>…</head><body>…</body></html>",
    "currentState": { "items": [ … ] }
  }
}
Element reference

Attributes, config and events

Everything goes through the element: two attributes in, two events out. The config is merged over the defaults, so pass only what you change.

Attributes

api-key
Your project API key. Sent as X-Api-Key with every request the editor makes.
config
A JSON string (or an object, when set from JavaScript), merged over the defaults. Changes are applied live.

Common config keys

size
Canvas size in inches, e.g. {"w":6,"h":4}. Default 11×6.
htmlButtonBehaviour
"download" (default) downloads the active side as a file. "save" fires html-button-click instead.
user_id
Your id for the end user. Keeps each user's uploaded images separate.
merge_variables
Fields for the merge picker: [{ merge_tag, type: "text" | "image", default_value }].
initial_html
An HTML string or URL to open, e.g. a design saved earlier.
template_scope
Show only the templates in this scope (see the API below).
appearance
Colours, corner rounding and fonts, so the editor matches your product.
address_box
Address block settings. Set isLetter: true for 8.5×11 letters.

Events

html-button-click
The user saved. event.detail[0] is { front, back }, each with HTMLContent. Fires only when htmlButtonBehaviour is "save".
exit
The user confirmed leaving the editor. Close or hide it.
API reference

Templates and scopes

Base URL https://designertool.io/api. Send your project API key in the X-Api-Key header; requests must come from one of the project's allowed domains. Scopes decide which templates an end user sees: pass the scope name as template_scope in the element config.

Method Path What it does
GET/project/templatesList the templates available to your project, with search, category_id, size and side filters and paging. Honours the X-Template-Scope header.
GET/project/templates/{id}One template, including its HTML.
GET/project/templates/categoriesYour template categories.
PUT/scopes/templatesReplace the templates in a scope. Body: { scope, templates: [ids] }.
POST/scopes/templates/addAdd templates to a scope.
DELETE/scopes/templates/removeRemove templates from a scope.
Free to try · no card · no per-postcard fee

Get sandbox keys in a minute.

Free, no card, no expiry. Three watermarked exports a month until you're ready for production.

Passes Lob and PostGrid preflight Cancel any time Sandbox keys never expire