API referenceLetters

Verify a letter PDF's layout before sending

Layout-verifies a letter BEFORE it is sent and returns a structured verdict — no side effects, nothing stored, nothing mailed, nothing charged.

Endpoint
POST https://api.dairo.app/v1/letters/verify

Layout-verifies a letter BEFORE it is sent and returns a structured verdict — no side effects, nothing stored, nothing mailed, nothing charged. Checks: every page is A4 portrait; the recipient address sits inside the address window (left x=22mm y=60mm 85.5×25.5mm; right x=118mm — mm from the top-left corner; REGISTERED letters use the registered window y=67–90mm below the carrier's label band); the franking keep-out, 5mm edge band, 15mm bottom-left corner, and left-margin routing-code zone are clear; fonts are embedded; no interactive form fields; and, when to is provided, the address PRINTED in the PDF matches the intended recipient (the carrier mails to what is printed). Accepts the same document sources as the create — pass the SAME delivery and payment you will send with, so the templateId source verifies the exact PDF a create with the same inputs would mail. Every agent should call this before a real send and fix every fail (and review every warn). Requires only letters:read. For a templateId source the checks include clipped_content, which fails when the render cut text off; it is skipped for a caller-supplied PDF.

Scope: letters:read. Send the API key as a bearer token; Scopes lists what each one reaches.

Request

cURL
curl -X POST "https://api.dairo.app/v1/letters/verify" \
  -H "Authorization: Bearer $DAIRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Body

Required, application/json: LetterVerifyRequest.

Exactly one document source must be provided: pdfBase64, file, or templateId (with templateData + to — the render composites the recipient). Passing to is strongly recommended: it enables the printed-address match check.

FieldTypeRequiredDescription
pdfBase64string or nullnoBase64-encoded PDF to verify (max 4 MB for verification).
fileLetterFileRef or nullno
templateIdstring or nullnoVerify a stored template's render. Requires to.
templateDataobject or nullno
toPostalAddress or nullnoThe intended recipient — enables the printed-address match check. Required with templateId.
fromPostalAddress or nullnoOptional return address (template path only).
printLetterPrintOptionsno
maxPagesinteger or nullnoOptional page-count ceiling enforced as a fail check. (minimum 1)
deliveryLetterDelivery or nullnoPass the SAME delivery class you will send with. registered letters use a DIFFERENT address geometry — the carrier prints its registered-mail label into y=50–67mm, so the recipient block must sit in y=67–90mm — and are verified against it. Registered delivery is domestic only (the recipient must be in the print centre country, DE); with to in another country verify adds a failing registered_domestic check, and price/create reject it with 422, param delivery.
paymentLetterPayment or nullnoThe structured payment object the create will carry. Template letters are rendered WITH the generated slip so the verified PDF is the exact PDF the create would mail. Template-path only (mirrors the create's rule).

Response

200 Success. Body: application/json, LetterVerification.

FieldTypeRequiredDescription
object"letter_verification"yes
validbooleanyesTrue when NO check failed. Warnings may still be present.
pageCountintegerno
pageSizeobject or nullnoPage size in mm. A page within 1 mm of A4 is reported as exactly 210 x 297 with format A4.
measuredPageSizeobject or nullnoThe raw measured page size, present when pageSize was reported as nominal A4 (a page within 1 mm of 210 x 297 mm, e.g. Chromium's 596 pt width).
addressPlacement"left", "right", nullnoThe window where the recipient address was detected, or null when none was found.
addressLinesarray of stringnoThe text lines detected inside the address window, top to bottom.
checksarray of LetterVerificationCheckyes
summarystringno
agentHintstringnoThe recommended next step.
200
{
  "object": "letter_verification",
  "valid": true,
  "pageCount": 0,
  "pageSize": {
    "widthMm": 0,
    "heightMm": 0
  },
  "measuredPageSize": {},
  "addressPlacement": "left",
  "addressLines": [
    "string"
  ],
  "checks": [
    {
      "id": "string",
      "status": "pass",
      "message": "string",
      "expected": "string",
      "actual": "string"
    }
  ],
  "summary": "string",
  "agentHint": "string"
}

Errors

Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.

StatusMeaning
400The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch).
401The API key is missing or invalid.
403The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted).
404No such resource in this account (resource_not_found).
413The request body or an attachment is too large (payload_too_large, plan_limit_reached).
422The request is well-formed but a field failed validation (validation_failed).
429Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached).
500An unexpected error; retry with backoff, then contact support (internal_error).

On this page