---
title: Send a physical letter from code in 5 minutes
description: PostalForm lets software create reviewable physical-mail drafts, hand the sender to hosted checkout, and check fulfillment status after payment. Hosted checkout is the default because real mail has real-world side effects.
seotitle: PostalForm Developer Quickstart | Send physical mail from code
seo-description: Create reviewable PostalForm mail drafts, test without real postage, and check order status with hosted checkout as the default safe flow.
group: resources
indexable: true
nav: false
schema: software
eyebrow: Developer quickstart
published: 2026-06-28
updated: 2026-06-28
path: /developers/quickstart
---
# Send a physical letter from code in 5 minutes

PostalForm lets software create reviewable physical-mail drafts, hand the sender to hosted checkout, and check fulfillment status after payment. Hosted checkout is the default because real mail has real-world side effects.

## Fast answer
Use the API when your product needs to generate a mailing draft, preview the packet, collect human review and payment, then follow the mail lifecycle. Use test mode while developing: it creates a watermarked preview PDF, fake quote, and fake tracking events without charging or submitting to a print provider.

## Before you start
- Decide whether your first draft is plain text, a PDF URL, or a guided form workflow.
- Generate a stable `Idempotency-Key` for every create request.
- Keep hosted checkout as the default path for production mail unless you are deliberately using a machine-payment flow.
- Store the returned order or draft ID so retries and status checks do not create duplicate mail.

## 1. Create a draft letter
```bash
curl -X POST https://www.postalform.com/v1/test/mail_drafts \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8c9f7b7a-9e7d-4a85-96d8-b2d2336a6b1f" \
  -d '{
    "letter_text": "Hello from PostalForm test mode.",
    "sender": {
      "name": "Avery Sender"
    },
    "recipient": {
      "name": "Riley Recipient"
    }
  }'
```

The response includes a `preview_pdf_url`, a fake zero-dollar quote, and fake tracking events. The preview PDF is watermarked `TEST MODE`.

## 2. Create a draft from a PDF URL
```bash
curl -X POST https://www.postalform.com/v1/test/mail_drafts \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 48a26971-efde-42ef-bb3f-f1d29b4b398c" \
  -d '{
    "pdf_url": "https://example.com/packet.pdf",
    "mail_class": "certified"
  }'
```

Production draft creation should still route to a human review and hosted checkout step before PostalForm submits anything to a provider.

## 3. Create a guided form draft
```bash
curl -X POST https://www.postalform.com/v1/test/form_drafts \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 08f54053-0d06-4d4a-b6c5-3391ac45fbbf" \
  -d '{
    "workflow_slug": "debt-validation-packets",
    "answers": {
      "collector_name": "Example Debt Collector"
    }
  }'
```

Use this shape for packet workflows where the user answers questions and PostalForm generates a reviewable PDF before checkout.

## 4. Check order status
```bash
curl https://www.postalform.com/v1/test/orders/test_mail_example
```

Test status responses include fake lifecycle events. Production status checks return the real mail order state after checkout and provider submission.

## Idempotency
Send `Idempotency-Key: <uuid>` on create requests. Agents, queue workers, and retrying integrations should reuse the same key for the same intended mailing so network retries do not duplicate a draft or a real order.

## Test mode guarantees
- Generates a watermarked preview PDF.
- Returns a fake quote and fake tracking events.
- Never submits to a print provider.
- Never charges real money.
- Keeps the response shape close to production integrations.

## Webhook events to expect
Production integrations should be ready to receive lifecycle events such as `mail.order.created`, `mail.order.paid`, `mail.order.submitted`, `mail.order.provider_accepted`, `mail.order.provider_rejected`, `mail.order.mailed`, `mail.order.tracking_updated`, `mail.order.delivery_attempted`, `mail.order.delivered`, `mail.order.failed`, and `mail.order.refunded`.

## Common errors
- Missing idempotency key: generate and persist one before creating a draft.
- Real-mail side effects: keep hosted checkout in the loop unless the customer explicitly opted into a machine-payment path.
- Duplicate retries: reuse the same idempotency key for the same intended mailing.
- Unverified recipient data: validate addresses before production checkout.


## Ready to send it?
Test mode creates previews and fake tracking without charging money or sending real mail.

[Create a test draft](/v1/test/mail_drafts)
