Layout & verification
The exact PDF layout a printed letter needs — address window, keep-out zones, fonts — plus the verify endpoint that checks a PDF before you send it.
A letter is printed exactly as your PDF renders, folded into a window envelope, and the recipient address is read optically from page 1 of the PDF. That means the address must sit inside the envelope window, and a few zones must stay clear for franking and postal processing. This page is the full layout contract — and the two endpoints that make it painless:
| Operation | Method & path | Scope |
|---|---|---|
| Get requirements | GET /v1/letters/requirements | letters:read |
| Verify a letter | POST /v1/letters/verify | letters:read |
Building with an AI agent? Point it at GET /v1/letters/requirements
first: the response carries this whole spec machine-readable, plus ready-made
compliant starter templates it can store and send immediately. Over MCP the
same lives on the prepare_letters tool (action: "requirements" and
action: "verify"). An agent needs zero prior knowledge of postal layout
standards.
The three ways to get a compliant PDF
- Use a starter template (easiest).
GET /v1/letters/requirementsreturnsstarterTemplates[]— compliant letter HTML with{{placeholders}}. Store one viaPOST /v1/letters/templates, then send withtemplateId+templateData+to. Dairo composites the recipient into the window for you; the layout is guaranteed. - Store your own template. Write your own HTML (brand, layout, fonts) that keeps the zones below clear, store it as a letter template, and let Dairo render + place the address.
- Bring your own PDF. Generate the PDF with any toolchain (HTML-to-PDF,
LaTeX, ReportLab, a word processor) following the spec below — including
placing the recipient address yourself — and pass it as
pdfBase64orfile.
Whichever path you take: verify before you send.
Page setup
| Rule | Value |
|---|---|
| Format | A4 portrait — 210 × 297 mm, every page |
| Max file size | 25 MB (POST /v1/letters), 4 MB for /verify |
| Fonts | Embed all fonts in the PDF |
| Encryption | None — no password protection |
| Address | Real text, not a scanned image (it is read from the PDF) |
| Template letters | Render as a single A4 page |
All coordinates below are measured in mm from the top-left corner of page 1.
The address window
The recipient address must sit entirely inside one window zone:
| Placement | x | y | Width | Height |
|---|---|---|---|---|
left (default) | 22 mm | 60 mm | 85.5 mm | 25.5 mm |
right | 118 mm | 60 mm | 85.5 mm | 25.5 mm |
Format the block left-aligned at 10–12 pt regular (never bold, underlined, or on a dark background — it is machine-read) with 1.2 line-height, no blank lines, at most 6 lines, in postal order: optional small return-address line (7 pt, underlined), name, company, street + house number (one line) or PO box, postal code + city (one line), then the country line described below. Keep a 3 mm left/right and 2 mm top/bottom inset inside the window. Prefer the left window — it is the postal network's standard machine-read field and the delivery-proven default.
The country line
Letters are printed and posted in Germany. A letter is domestic when the
recipient and the sender (from, if you give one) are both in Germany:
| Letter | Recipient block | Return-address line |
|---|---|---|
| Germany to Germany | no country line (DIN 5008) | no country |
| Switzerland to Germany | ends with GERMANY | ends with SWITZERLAND |
| Germany to Austria | ends with AUSTRIA | ends with GERMANY |
Any letter that is not domestic prints the country name in English
capitals, never the ISO code: GERMANY, SWITZERLAND, UNITED KINGDOM.
Template letters get this automatically. Follow the same rule in your own PDF.
GET /v1/letters/requirements returns it under
addressWindow.recipientFormat.countryLine.
Registered mail is different
On a delivery: "registered" letter the carrier prints its registered-mail
label and barcode into the y = 50–67 mm band of the address field. The
layout shifts:
| Element | Geometry |
|---|---|
| Return-address line | y 45–50 mm band (x 20–105 mm) |
| Carrier label + franking | y 50–67 mm — must stay empty |
| Recipient block | x 22, y 67, 85.5 × 23 mm |
Template letters get this automatically. For your own PDF, place the recipient
below 67 mm and verify with "delivery": "registered" — the verifier switches
to the registered geometry and fails a normal-position address block.
Registered mail always uses the left field and is domestic only. Domestic
means the recipient (to.country) is in Germany, where letters are printed
and posted. The sender's country does not matter. Price, send, batch send and
verify reject delivery: "registered" to any other country with a 422
naming delivery, and verify adds a failing registered_domestic check.
Use economy or priority for letters abroad.
When you send with templateId, Dairo composites the recipient from the
request's to into this window at render time — a template must never
contain an address of its own. The window only concerns you when you bring
your own PDF.
Keep-out zones
These zones must contain nothing (except the address block itself inside the franking zone):
| Zone | Geometry | Why |
|---|---|---|
Franking, left | x 20, y 40, 89.5 × 47.5 mm | Postage/franking marks are stamped here |
Franking, right | x 116, y 40, 89.5 × 47.5 mm | Same, for right-window letters |
| Page edges | 5 mm on all sides, every page | Printer hardware margin |
| Bottom-left corner | 15 × 15 mm | Postal processing marks |
| Left-margin routing code | x < 10 mm, y 124–134 mm | The carrier prints its sorting code here |
| Bottom band | 110 mm, only with a payment slip | The generated slip is composited here |
Two more PDF rules that bite in practice: no interactive form fields (AcroForm — flatten them, or the print output can lose content), and letters over 9 sheets ship unfolded in a C4 envelope automatically.
Body content is safest starting at y ≥ 100 mm with 25 mm left / 20 mm
right margins. The top band (y < 38 mm) is free for your letterhead, and the
area right of the franking zone fits a date/reference block. Start it at
x ≥ 125 mm, y 40–90 mm. That is the DIN 5008 info-block position the
din-classic starter uses. The franking keep-out itself ends at x = 109.5 mm.
Verify before sending
POST /v1/letters/verify takes the same document sources as the create
(pdfBase64, file, or templateId + templateData + to) and returns a
structured verdict — nothing is stored, mailed, or charged. Pass to so the
address printed in the PDF is matched against the intended recipient.
valid is true only when no check failed. A fail means the letter
will misprint or misroute — fix it. A warn means it will probably print but
carries a risk (content near the page edge, unusually small address text,
image-only pages the optical address reader may struggle with).
The checks: page_size, page_count, address_window, address_fit,
address_lines, address_font_size, address_match (with to),
franking_zone, edge_clearance, bottom_left_corner, routing_code_zone,
images_in_window, fonts_embedded, form_fields, clipped_content, and
registered_domestic for registered letters — each with the expected geometry
in mm in its message, so a failing PDF can be regenerated without consulting
anything else.
address_font_size holds the recipient lines to 10–12 pt and warns below
10 pt. The small return-address line at the top of the window (8.5 pt or
less, 7 pt in Dairo's own layout) is reported separately and is not held to
that range.
Clipped content
Text cut off by a box with overflow: hidden (or clip), or pushed past the
page edge, is simply missing from the printed letter, and the PDF geometry
alone cannot show it. A common cause is a body box with a fixed bottom or
height whose sign-off no longer fits. For template letters (templateId)
Dairo measures this on the rendered page: clipped_content fails when any
text extends beyond the box that clips it or beyond the page, and lists each
clipping element with a short path, the first 40 characters of the box's
text (boxText), its position (boxTopMm, boxLeftMm), the clipped text,
and how far it overflows in mm. Boxes that only crop images or shapes (a logo crop) are not
reported. For a PDF you supply (pdfBase64 or file) the check is skipped,
so make sure nothing in your own layout is cut off.
reason is overflow_clip for an element with overflow: hidden/clip, and
beyond_page (with path: "page") for text past the A4 page edge.
Sending a template letter whose text is cut off is rejected before anything is stored or charged:
Let the box grow, shorten the text, or reduce the font size, then verify again.
The safe sending workflow
GET /v1/letters/requirements— spec + starter templates (agents: start here).- Build the document (template or your own PDF).
POST /v1/letters/verify— fix everyfail, review everywarn.POST /v1/letters/price— preview the cost.POST /v1/letterswithdryRun: true— a full no-send rehearsal: validated, rendered, priced; never mailed, never charged.POST /v1/letters— the real send, with anIdempotency-Key.
Next steps
- Letter templates — store branded, reusable letter HTML.
- Print & delivery options — color, duplex, registered mail, payment slips.
- Send a letter — the create call itself.