<!-- SKILL-VERSION: library/statement-v1 3a76850@2026-10-04T07:41:12+10:00 -->
> **Skill version:** `3a76850@2026-10-04T07:41:12+10:00` (`library/statement-v1`).
> If you have a cached copy of this skill with a different version token,
> discard it and use this copy. Re-fetch this URL at the start of each
> session to detect updates.

# makesPDF — Statement skill `statement-v1`

> Version: `statement-v1`. **Immutable** — this file never changes after
> release. Fixes land in `statement-v2`, served alongside this file. If a
> newer version exists, it is noted at the top of this file; this URL
> keeps serving regardless.

> **Note to AI agents:** this document is served over HTTP at
> `https://makespdf.com/skills/library/statement-v1.md` (or
> `http://localhost:8788/skills/library/statement-v1.md` in dev). It is
> **not a local file.** Re-fetch it with a web fetch / HTTP tool — do
> **not** call your filesystem `Read` tool with `/skills/...`. Paths
> that begin with `/api/v1/` or `/skills/` below are URL paths relative
> to the makespdf origin, not filesystem paths.

Read [`/skills/pdf-template-author.md`](https://makespdf.com/skills/pdf-template-author.md)
first for the builder DSL, style properties, and the preview/render loop.
This file is the statement-specific companion: which fields to use,
which library template to start from, and a worked fetch, fill, render
example.

A statement of account summarises transactions over a period (opening
balance, charges, credits, closing balance, aging). For a single bill,
use the invoice skill instead.

## Canonical fields (field registry)

Source: `docs/field-registry.md` and
`apps/web/src/utils/field-registry.ts` (`documentTypes` containing
`"statement"`). Use these canonical ids when naming data keys. The
`Aliases` column lists common incoming names the registry already
recognises — prefer the canonical id for new data.

### Document identity

| Canonical id       | Label            | Type / format | Common aliases                             |
| ------------------ | ---------------- | ------------- | ------------------------------------------ |
| `statement-number` | Statement Number | string        | statementno, statementid                   |
| `document-date`    | Date             | date          | date, statementdate, issuedate             |
| `due-date`         | Due Date         | date          | duedate, paymentdue                        |
| `currency`         | Currency         | code          | currencycode, cur                          |
| `period-from`      | Period From      | date          | periodstart, startdate, billingperiodstart |
| `period-to`        | Period To        | date          | periodend, enddate, billingperiodend       |

### Seller and buyer

| Canonical id           | Label           | Type / format | Common aliases                      |
| ---------------------- | --------------- | ------------- | ----------------------------------- |
| `seller-name`          | Company Name    | string        | companyname, vendorname             |
| `seller-address`       | Company Address | string        | companyaddress, vendoraddress       |
| `seller-phone`         | Phone           | phone         | phone, mobile, tel                  |
| `seller-email`         | Email           | email         | email, companyemail                 |
| `seller-tax-id`        | Tax ID          | tax-id        | gstin, vat, ein, abn                |
| `seller-logo`          | Logo            | url           | logo, companylogo                   |
| `buyer-name`           | Client Name     | string        | customername, accountholder         |
| `buyer-address`        | Client Address  | string        | customeraddress, billingaddress     |
| `buyer-email`          | Client Email    | email         | customeremail, billingemail         |
| `buyer-account-number` | Account Number  | string        | accountnumber, customerid, clientid |

### Transactions (one row per entry)

| Canonical id           | Label       | Type / format | Common aliases                       |
| ---------------------- | ----------- | ------------- | ------------------------------------ |
| `item-date`            | Entry Date  | date          | entrydate, workdate, transactiondate |
| `item-description`     | Description | string        | description, details                 |
| `item-charges`         | Charges     | currency      | charges, debit, debits               |
| `item-credits`         | Credits     | currency      | credits, credit, payments            |
| `item-running-balance` | Balance     | currency      | runningbalance, balance              |

### Totals and aging

| Canonical id      | Label           | Type / format | Common aliases                  |
| ----------------- | --------------- | ------------- | ------------------------------- |
| `opening-balance` | Opening Balance | currency      | previousbalance, broughtforward |
| `closing-balance` | Closing Balance | currency      | endingbalance, currentbalance   |
| `total-charges`   | Total Charges   | currency      | totaldebits, totalinvoiced      |
| `total-credits`   | Total Credits   | currency      | totalpayments, totalcredited    |
| `amount-paid`     | Amount Paid     | currency      | paid, totalpaid                 |
| `amount-due`      | Amount Due      | currency      | balancedue, outstanding         |
| `aging-current`   | Current         | currency      | current, agingcurrent           |
| `aging-30`        | 30 Days         | currency      | 30days, 31to60                  |
| `aging-60`        | 60 Days         | currency      | 60days, 61to90                  |
| `aging-90`        | 90 Days         | currency      | 90days, aging90                 |
| `aging-90-plus`   | 90+ Days        | currency      | over90, 90plus                  |

### Notes

| Canonical id           | Label                | Type / format | Common aliases        |
| ---------------------- | -------------------- | ------------- | --------------------- |
| `notes`                | Notes                | string        | notes, memo, remarks  |
| `payment-instructions` | Payment Instructions | string        | howtopay, bankdetails |

## Library template

Start from **`statement-bank`** (institution letterhead, account header
strip, transaction table with running balance, charges/credits
summaries, aging schedule). An account-summary variation exists
(`statement-account-summary`) — list it with
`GET /api/v1/templates?owner=library&category=statement`.

## Worked example: fetch, fill, render

All calls need `Authorization: Bearer $MAKESPDF_API_KEY`.

**1. Fetch the template's DSL and sample data.**

```sh
curl -s -H "Authorization: Bearer $MAKESPDF_API_KEY" \
  "https://makespdf.com/api/v1/templates/statement-bank"
# -> { templateId, name, dsl, sampleData, ... }
```

**2. Fill.** Start from the returned `sampleData`, keep its keys, replace
the values with the real period. Map incoming names to the canonical
ids above (`debits` -> Charges, `previousbalance` -> Opening Balance).
Minimal override shape:

```json
{
  "statementNumber": "ST-2026-08-114",
  "period": { "label": "August 2026" },
  "issuedOn": "2026-09-02",
  "institution": { "name": "Pacific Commerce Bank" },
  "openingBalance": 4210.55,
  "closingBalance": 6188.2,
  "amountDue": 6188.2,
  "transactions": [
    { "date": "2026-08-04", "desc": "Invoice INV-2026-0398", "debit": 2400.0, "balance": 6610.55 }
  ]
}
```

**3. Render.** Production path is the stored template (billed, 1 credit
per 10 pages):

```sh
curl -s -X POST https://makespdf.com/api/v1/render \
  -H "Authorization: Bearer $MAKESPDF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"templateId": "statement-bank", "data": {...}}' -o statement.pdf
```

Iterating on a customised fork? Draft it free with
`POST /api/v1/preview { dsl, data }`, pre-flight with
`POST /api/v1/preview/validate`, then save via
`POST /api/v1/templates { dsl, name }` and render your copy.

## Traps

- Date columns need width budget: full-format dates (`"2 March 2026"`)
  need ~18% of the content width at 10pt; short formats fit 10-12%.
  See the Statement recipe in `/skills/pdf-recipes.md`.
- Debit/credit cells render conditionally — an empty cell must stay
  blank, never the literal string `undefined`. See the recipe's
  `when()` pattern.
- Do not pass the transaction `cols` grid into `totals()` here:
  statement total labels are long and need the default 60/25/15 split.
