---
title: "Send any PDF by post"
method: POST
path: "/letters"
tags: ["Letters"]
---

# Send any PDF by post

`POST /letters`

## Request

- Base URL: `https://api.vocal.email/v1`
- URL: `https://api.vocal.email/v1/letters`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer
- TypeScript: <https://skmtc.dev/vocal/apis/magic-heidi-invoicing-software-api/docs/letters/post.ts> (a function with typed inputs; its response is checked against the schema)

Uploads the previewed PDF directly to Pingen with automatic sending, color duplex printing, and economical postage. Pingen reads the destination from the PDF. No country restriction, billing, worker, or local PDF storage. Reuse one Idempotency-Key per send action to prevent duplicates. processing means Pingen accepted the PDF and is analysing it; dispatch is confirmed by webhook.

## Headers

- `Idempotency-Key` string, required

## Request body `multipart/form-data`

- object
  - `documentType` string: Optional free-form label, e.g. invoice, reminder, contract, or report.
  - `invoiceId` string: Optional invoice owned by the authenticated account.
  - `invoiceStatus` string: Legacy alias of documentType; values must match if both are provided.
  - `pdf` string, binary, required

## Response `202`

Pingen accepted the PDF, or this action already exists

- object
  - `data` Letter
    - `deliveredAt` string, date-time, nullable
    - `dispatchedAt` string, date-time, nullable
    - `documentType` string: Optional free-form label, e.g. invoice, reminder, contract, or report.
    - `environment` 'production' | 'staging'
    - `error` object, nullable
    - `failedAt` string, date-time, nullable
    - `id` string
    - `invoiceId` string, nullable
    - `invoiceSnapshot` object
    - `invoiceStatus` string, nullable: Legacy document-type field for invoice-linked letters.
    - `recipientAddress` string, nullable
    - `recipientCountry` string, nullable
    - `requestedAt` string, date-time, nullable
    - `status` 'sending' | 'processing' | 'dispatched' | 'delivered' | 'failed' | 'undeliverable' | 'needs_review'
    - `undeliverableAt` string, date-time, nullable
    - `updatedAt` string, date-time, nullable
  - `success` boolean

## Other responses

- `400`: Invalid request
- `401`: Authentication required
- `403`: Invalid provider signature or organisation
- `404`: Resource not found
- `409`: Idempotency-Key reused with different content
- `413`: PDF exceeds 20 MB
- `500`: Persistence failure
- `502`: Submission could not be confirmed; check history before resending
- `503`: Provider/configuration unavailable

## Changes

- **2026-09-11** `f2a5ce43a2df`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/vocal/apis/magic-heidi-invoicing-software-api/changes/letters/post.md)

---

[API](https://skmtc.dev/vocal/apis/magic-heidi-invoicing-software-api.md) - [All operations](https://skmtc.dev/vocal/apis/magic-heidi-invoicing-software-api/llms.txt) - [OpenAPI document](https://skmtc.dev/vocal/apis/magic-heidi-invoicing-software-api/revisions/d0319ad57804?raw)
