← All recipes

Coupon

Lay several tear-off coupons onto one sheet. You learn EAN-13 barcodes, background colours and opacity, and multiplying copies with a repeating section.

Use this template

What this teaches

  • code-ean13
  • style-bg
  • style-opacity
  • node-circle
  • block-repeat

Building it in the editor

  1. Make one coupon as a rectangle and put the offer, the barcode and the expiry inside it.
  2. Set the rectangle to repeat over data.coupons with the item named cp. The copies stack down the sheet.
  3. Add a code object and choose EAN-13. The value must be 12 or 13 digits — anything else cannot be drawn.
  4. Lay a pale background and overlay a large discount figure at low opacity. This is not about saving ink — it is about separating what is read from what is decoration.
  5. Add a circle to mark the tear point. A shape needs nothing but a colour and a thickness.

Building it with the schema and API

  1. Set codeKind to "ean13". Put digits only in props.text — outside the length the standard defines it cannot be drawn.
  2. A repeating section is props.repeat on a rect. Copies stack downward and continue onto the next page when they run out of room.
  3. styles[].opacity runs from 0 to 1. It lives on the style, not the node, so everything sharing that style fades together.

The finished document

The JSON below is exactly the document those two routes produce. Our tests validate it and check that it renders without warnings, so you can paste it and use it as is.

EXAMPLE
{
  "v": 1,
  "unit": "px",
  "page": {
    "size": "a4",
    "orientation": "portrait",
    "margin": {
      "t": 32,
      "r": 32,
      "b": 32,
      "l": 32
    },
    "header": "",
    "footer": ""
  },
  "fonts": [],
  "styles": [
    {
      "id": "s_card",
      "fontFamily": "Liberation Sans",
      "fontSize": 12,
      "fontWeight": 400,
      "italic": false,
      "color": "#111111",
      "bg": "#fff8e6",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 12,
      "opacity": 1
    },
    {
      "id": "s_off",
      "fontFamily": "Liberation Sans",
      "fontSize": 54,
      "fontWeight": 700,
      "italic": false,
      "color": "#c9a227",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 0.35
    },
    {
      "id": "s_h",
      "fontFamily": "Liberation Sans",
      "fontSize": 18,
      "fontWeight": 700,
      "italic": false,
      "color": "#111111",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_l",
      "fontFamily": "Liberation Sans",
      "fontSize": 12,
      "fontWeight": 400,
      "italic": false,
      "color": "#555555",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_cap",
      "fontFamily": "Liberation Sans",
      "fontSize": 10,
      "fontWeight": 400,
      "italic": false,
      "color": "#888888",
      "bg": "transparent",
      "align": "center",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    }
  ],
  "nodes": [
    {
      "id": "n_card",
      "parent": "",
      "order": 0,
      "type": "rect",
      "x": 0,
      "y": 0,
      "w": 697,
      "h": 190,
      "show": "",
      "styleId": "s_card",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#c9a227",
        "fill": "#fff8e6",
        "repeat": "data.coupons",
        "as": "cp",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "One coupon"
    },
    {
      "id": "n_logo",
      "parent": "n_card",
      "order": 1,
      "type": "image",
      "x": 20,
      "y": 18,
      "w": 100,
      "h": 50,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "",
        "src": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAgNjAiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iNjAiIHJ4PSI4IiBmaWxsPSIjMWYyOTM3Ii8+PHRleHQgeD0iNjAiIHk9IjM4IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TE9HTzwvdGV4dD48L3N2Zz4=",
        "fit": "contain",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Logo"
    },
    {
      "id": "n_off",
      "parent": "n_card",
      "order": 2,
      "type": "label",
      "x": 400,
      "y": 20,
      "w": 280,
      "h": 70,
      "show": "",
      "styleId": "s_off",
      "props": {
        "text": "{{ cp.off }}%",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Discount"
    },
    {
      "id": "n_h",
      "parent": "n_card",
      "order": 3,
      "type": "label",
      "x": 20,
      "y": 82,
      "w": 360,
      "h": 24,
      "show": "",
      "styleId": "s_h",
      "props": {
        "text": "{{ cp.title }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Offer"
    },
    {
      "id": "n_exp",
      "parent": "n_card",
      "order": 4,
      "type": "label",
      "x": 20,
      "y": 108,
      "w": 360,
      "h": 18,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "Valid until {{ cp.expires }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Expiry"
    },
    {
      "id": "n_bar",
      "parent": "n_card",
      "order": 5,
      "type": "code",
      "x": 400,
      "y": 100,
      "w": 260,
      "h": 62,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "{{ cp.barcode }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "ean13",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Barcode"
    },
    {
      "id": "n_cut",
      "parent": "n_card",
      "order": 6,
      "type": "circle",
      "x": 330,
      "y": 178,
      "w": 12,
      "h": 12,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#c9a227",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Tear point"
    }
  ]
}

The request body. Put the document above into template and the data below into data.

REQUEST
{
  "template": "(the document above)",
  "data": {
    "coupons": [
      {
        "title": "First order",
        "off": 20,
        "expires": "2026-12-31",
        "barcode": "8801234567893"
      },
      {
        "title": "Thanks for coming back",
        "off": 10,
        "expires": "2026-10-31",
        "barcode": "8801234567909"
      },
      {
        "title": "Refer a friend",
        "off": 15,
        "expires": "2026-11-30",
        "barcode": "8801234567916"
      }
    ]
  }
}