← レシピ一覧

Credit note

Build a credit note that reverses an invoice you already issued. You learn how to reference the original, an overlay stamp using opacity, and how to receive the PDF bytes instead of a URL.

このテンプレートを取り込む

このレシピで身につくこと

  • style-opacity
  • expr-string
  • api-export-file
  • expr-format-currency

エディタで作る

  1. Start by duplicating the invoice template — a credit note is the same table with the sign reversed.
  2. Change the title to Credit note and reference the original number below it. {{ upper(data.origin) }} normalises the case so it is easy to compare by eye.
  3. Add another label reading "VOID" in a large size and drop its opacity to 0.12. Overlaid on the body it does not obscure the text.
  4. Overlap order comes from the object tree. Bring the stamp to the front so it sits over the body.
  5. The amounts arrive negative. Currency formatting renders negatives by the rules of the locale, so there is nothing extra to do.

スキーマと API で作る

  1. If your accounting system needs the file directly, send export_type "file". The response body is the PDF itself with content-type application/pdf.
  2. "file" works only on POST /v1/create. Async and batch reject it, because there is no file yet at the moment we answer.
  3. Any other value is rejected rather than quietly defaulting — a silently ignored option hides your typo forever.
  4. String helpers such as upper, lower, trim, sub, replace, pad and split are available in expressions. replace takes literals only — no regular expressions.

出来上がったドキュメント

下の JSON は、2 つの道筋が生むドキュメントそのものです。テストがこれを検証し、警告なしでレンダリングされることも確認しているので、そのまま貼り付けてお使いいただけます。

例
{
  "v": 1,
  "unit": "px",
  "page": {
    "size": "a4",
    "orientation": "portrait",
    "margin": {
      "t": 48,
      "r": 48,
      "b": 56,
      "l": 48
    },
    "header": "",
    "footer": "{{ data.company }} · [[page]] / [[pages]]"
  },
  "fonts": [],
  "styles": [
    {
      "id": "s_h1",
      "fontFamily": "Liberation Sans",
      "fontSize": 26,
      "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": 13,
      "fontWeight": 400,
      "italic": false,
      "color": "#333333",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_tbl",
      "fontFamily": "Liberation Sans",
      "fontSize": 12,
      "fontWeight": 400,
      "italic": false,
      "color": "#111111",
      "bg": "transparent",
      "align": "left",
      "valign": "middle",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_total",
      "fontFamily": "Liberation Sans",
      "fontSize": 18,
      "fontWeight": 700,
      "italic": false,
      "color": "#111111",
      "bg": "transparent",
      "align": "right",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_void",
      "fontFamily": "Liberation Sans",
      "fontSize": 96,
      "fontWeight": 700,
      "italic": false,
      "color": "#d92d20",
      "bg": "transparent",
      "align": "center",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 0.12
    }
  ],
  "nodes": [
    {
      "id": "n_title",
      "parent": "",
      "order": 0,
      "type": "label",
      "x": 0,
      "y": 0,
      "w": 460,
      "h": 34,
      "show": "",
      "styleId": "s_h1",
      "props": {
        "text": "Credit note",
        "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": "Title"
    },
    {
      "id": "n_origin",
      "parent": "",
      "order": 1,
      "type": "label",
      "x": 0,
      "y": 42,
      "w": 460,
      "h": 20,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "Refund against invoice {{ upper(data.origin) }}",
        "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": "Original"
    },
    {
      "id": "n_items",
      "parent": "",
      "order": 2,
      "type": "table",
      "x": 0,
      "y": 96,
      "w": 697,
      "h": 130,
      "show": "",
      "styleId": "s_tbl",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#c9ced6",
        "fill": "#f3f5f7",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 6,
        "padX": 8,
        "align": "",
        "valign": "middle",
        "wrap": "",
        "bind": "data.items",
        "headerHeight": 28,
        "rowHeight": 24,
        "max": 100,
        "columns": [
          {
            "header": "Refunded item",
            "cell": "{{ item.name }}",
            "width": 497,
            "align": "left"
          },
          {
            "header": "Amount",
            "cell": "{{ format(item.amount, \"currency\", \"USD\", \"en-US\") }}",
            "width": 200,
            "align": "right"
          }
        ],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Refunded items"
    },
    {
      "id": "n_total",
      "parent": "",
      "order": 3,
      "type": "label",
      "x": 0,
      "y": 240,
      "w": 697,
      "h": 26,
      "show": "",
      "styleId": "s_total",
      "props": {
        "text": "Refund total {{ format(sum(data.items, \"amount\"), \"currency\", \"USD\", \"en-US\") }}",
        "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": "Total"
    },
    {
      "id": "n_void",
      "parent": "",
      "order": 4,
      "type": "label",
      "x": 0,
      "y": 300,
      "w": 697,
      "h": 120,
      "show": "",
      "styleId": "s_void",
      "props": {
        "text": "VOID",
        "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": "Void stamp"
    }
  ]
}

リクエストの本文です。上のドキュメントを template に、下のデータを data に入れてください。

リクエスト
{
  "template": "(the document above)",
  "data": {
    "company": "brewmypdf",
    "origin": "inv-2026-0042",
    "items": [
      {
        "name": "Maintenance (3 months) refund",
        "amount": -840
      },
      {
        "name": "Over-billing adjustment",
        "amount": -120
      }
    ]
  },
  "export_type": "file"
}