---
title: "Send a letter"
method: POST
path: "/v1/letters"
tags: ["mail"]
---

# Send a letter

`POST /v1/letters`

## Request

- Base URL: `https://api.noerrands.com/c/mail`
- URL: `https://api.noerrands.com/c/mail/v1/letters`
- Auth: HTTP bearer

Print and mail a physical letter through the USPS. CONSEQUENTIAL and charged: from 249 credits, plus 30 per extra page, 50 for color, 950 for certified, 699 over 6 sheets; a pdf_url is priced on its real page count. A mailed letter cannot be recalled. Sensitive write: it requires the human's approval of the recipient, content and price. A replay with the same idempotency_key returns the original result and never mails twice.

## Request body

- object
  - `to` object, required: A US postal address. US-only in v0.
    - `name` string, required: Recipient or sender name, 1-40 characters.
    - `company` string: Optional company line, up to 40 characters.
    - `line1` string, required: Street address, up to 64 characters.
    - `line2` string: Apartment, suite, or unit, up to 64 characters.
    - `city` string, required
    - `state` string, required: Two-letter US state code.
    - `zip` string, required: ZIP code, 5 digits or ZIP+4.
    - `country` 'US': US only in v0.
  - `from` object, required: A US postal address. US-only in v0.
    - `name` string, required: Recipient or sender name, 1-40 characters.
    - `company` string: Optional company line, up to 40 characters.
    - `line1` string, required: Street address, up to 64 characters.
    - `line2` string: Apartment, suite, or unit, up to 64 characters.
    - `city` string, required
    - `state` string, required: Two-letter US state code.
    - `zip` string, required: ZIP code, 5 digits or ZIP+4.
    - `country` 'US': US only in v0.
  - `subject` string: Optional subject line printed above the body.
  - `body_markdown` string: Letter body as Markdown. Exactly one of body_markdown, body_html or pdf_url.
  - `body_html` string: Letter body as HTML. Sanitized server-side: scripts, event handlers and external stylesheets are stripped.
  - `pdf_url` string, uri: HTTPS URL of a print-ready PDF to mail as-is.
  - `color` boolean
  - `double_sided` boolean
  - `certified` boolean
  - `idempotency_key` string: Use one key per human request. Replays within 24 hours return the original result instead of sending again.

## Response `200`

Success.

- object
  - `mail_id` string, required: Opaque id, "ml_...". Use it with get_mail_status.
  - `kind` 'letter' | 'postcard', required
  - `status` 'created' | 'processing' | 'in_transit' | 'delivered' | 'returned' | 'failed' | 'cancelled', required
  - `to` object, required: A US postal address as stored. After the 30-day retention window only city, state and the first 3 ZIP digits remain; name, company and street lines are permanently removed.
    - `name` string: Recipient or sender name, 1-40 characters.
    - `company` string: Optional company line, up to 40 characters.
    - `line1` string: Street address, up to 64 characters.
    - `line2` string: Apartment, suite, or unit, up to 64 characters.
    - `city` string, required
    - `state` string, required: Two-letter US state code.
    - `zip` string: ZIP code, 5 digits or ZIP+4 -- or just the first 3 digits once redacted.
    - `country` 'US': US only in v0.
  - `from` object, required: A US postal address as stored. After the 30-day retention window only city, state and the first 3 ZIP digits remain; name, company and street lines are permanently removed.
    - `name` string: Recipient or sender name, 1-40 characters.
    - `company` string: Optional company line, up to 40 characters.
    - `line1` string: Street address, up to 64 characters.
    - `line2` string: Apartment, suite, or unit, up to 64 characters.
    - `city` string, required
    - `state` string, required: Two-letter US state code.
    - `zip` string: ZIP code, 5 digits or ZIP+4 -- or just the first 3 digits once redacted.
    - `country` 'US': US only in v0.
  - `created_at` string, date-time, required
  - `expected_delivery_date` string, date: YYYY-MM-DD.
  - `credits_charged_cents` integer, required
  - `tracking_url` string, uri
  - `balance_cents` integer, required: Remaining credit balance after the charge.

## Other responses

- `400`: invalid_request
- `401`: unauthorized. Carries WWW-Authenticate: Bearer resource_metadata="..."
- `402`: insufficient_credits, with required_cents, topup_url and the credit packs.
- `403`: forbidden_scope: a write tool called with a read-only key.
- `404`: not_found
- `409`: idempotency_conflict
- `429`: rate_limited
- `502`: provider_error

---

[API](https://skmtc.dev/noerrands/apis/no-errands-mail-api.md) · [All operations](https://skmtc.dev/noerrands/apis/no-errands-mail-api/llms.txt) · [OpenAPI document](https://skmtc.dev/noerrands/apis/no-errands-mail-api/revisions/391e96e083f5?raw)
