Send a real letter from your app or your AI agent
Premier Letters writes letters, cards and postcards with a real pen and mails them via USPS — from $4.60 per letter, plus postage. Quote, preview, create and track orders with a REST API or a remote MCP server built for Claude, ChatGPT, and any MCP-compatible agent.
For AI assistants: connect in three calls
The user does not need to copy an API key. The assistant asks for one, the account owner approves a single email, and the assistant receives the key once.
connect_account(MCP, no key) orPOST /api/v1/agent/connectwith the user's email and your name. Show the user the returneduser_code.- The user approves the emailed link; meanwhile poll
check_connection(or thepoll_url) every 10–30 seconds until it returns theapi_key. create_orderwith the key, anidempotency_keyand areturn_address.
curl -X POST https://www.premierletters.com/api/v1/agent/connect \
-H "Content-Type: application/json" \
-d '{ "email": "owner@example.com", "agent_name": "Claude" }'
# 202 -> { request_id, poll_url, poll_secret, user_code, expires_at, instructions }
# Show the user user_code, then poll every 10-30 seconds:
curl "https://www.premierletters.com/api/v1/agent/connect/<request_id>?secret=<poll_secret>"
# -> { "status": "pending" } ... then once: { "status": "approved", "api_key": "pl_live_..." }Quick start
Generate a key at Settings → API keys, then validate an order (free, no charge) and create one when you're ready to send it.
1. Validate & price a letter
curl -X POST https://www.premierletters.com/api/v1/validate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer pl_live_xxxxx" \
-d '{
"message": "Dear Jane,\n\nThank you for your business.",
"recipients": [{
"first_name": "Jane", "last_name": "Doe",
"address_line1": "123 Main St", "city": "Austin", "state": "TX", "zip": "78701"
}]
}'2. Create and pay for the order
curl -X POST https://www.premierletters.com/api/v1/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer pl_live_xxxxx" \
-H "Idempotency-Key: thank-you-jane-001" \
-d '{
"message": "Dear Jane,\n\nThank you for your business.",
"recipients": [{
"first_name": "Jane", "last_name": "Doe",
"address_line1": "123 Main St", "city": "Austin", "state": "TX", "zip": "78701"
}],
"return_address": {
"name": "Acme Dental", "address_line1": "100 Congress Ave",
"city": "Austin", "state": "TX", "zip": "78701"
},
"payment": { "method": "checkout_session" }
}'Pricing is from $4.60 per letter, plus postage (passed through at face value). The first 300 characters are included; every additional 100 characters adds $0.75. We write and mail within 2 business days; USPS First-Class delivery then typically takes 3–5 business days.
Placing a correct order
Return address
Pass return_address on envelope orders, or omit it to use the account default. With neither, set no_return_address_ack: true or the order is refused (400 no_return_address_unacknowledged). The response says which was used in return_address.source.
DetailsPrinted output
options.output_mode is handwritten (default), printed_bw or printed_color for the letter body; options.envelope_output_mode prints the envelope. Quote either with /validate or get_pricing.
DetailsIdempotency
Send an Idempotency-Key header (or idempotency_key) on every order. A retry with the same key and body returns the original order (200, idempotent_replay: true); a different body is a 422, a retry still in flight is a 409.
DetailsTest mode
pl_test_ keys validate and price exactly like live keys but never create, charge or send anything: orders come back with test: true.
DetailsAgent connect
An assistant without a key calls POST /api/v1/agent/connect (or the connect_account tool); the owner approves by email; the assistant polls for the key, which is returned once.
DetailsBalance
GET /api/v1/balance reads the prepaid balance; POST /api/v1/balance/topup returns a checkout link to add funds. Paying with payment.method "balance" waives the small-order handling fee.
DetailsMCP server — for AI agents
A remote Model Context Protocol server at https://www.premierletters.com/api/mcp. Quoting, listing handwriting styles, verifying an address and connecting an account work with no key; previewing and creating an order need your API key as a bearer token. Stateless Streamable HTTP — no session setup required.
Add to Claude
- claude.ai → Settings → Connectors
- Add custom connector
- URL:
https://www.premierletters.com/api/mcp - Paste your API key as the bearer token
Add to ChatGPT
- Settings → Connectors (developer mode)
- Add MCP server
- URL:
https://www.premierletters.com/api/mcp - Provide your API key when prompted for auth
{
"mcpServers": {
"premier-letters": {
"url": "https://www.premierletters.com/api/mcp",
"headers": { "Authorization": "Bearer pl_live_xxxxx" }
}
}
}Example prompts
- Send a handwritten thank-you to Jane Doe at 123 Main St, Austin, TX 78701.
- How much would it cost to mail 50 postcards on premium paper?
- Preview what this letter will look like in the Classic style before I order it.
- Check the status of my last Premier Letters order.
MCP tools
connect_accountGet a Premier Letters API key without the user copying one by hand. Pass the user's email and your name; we email them a link to approve (they can sign up from it if they have no account). Then call check_connection with the returned request_id and poll_secret every 10-30 seconds until it returns the api_key (returned once). Show the returned user_code to the user so they can match it on the approval page. No account or key needed to call this.
check_connectionCheck whether the user approved a connect_account request. Returns status pending, denied, expired or claimed, or, exactly once, status approved with the api_key. Poll every 10-30 seconds.
get_pricingGet a live price quote for a Premier Letters order. Pass char_count (or letter_count for a rough estimate) plus optional mailing_option and paper_type to get a per-piece and total price, in cents. No account needed. Orders under 5 pieces carry a $0.99 per-piece handling fee (included in total_cents), waived when paid from a prepaid balance. Pass output_mode (printed_bw / printed_color) to quote a printed letter body instead of a pen-written one, and envelope_output_mode to quote a printed envelope.
list_handwriting_stylesList available handwriting styles (fonts) for a letter order. Use the returned "id" as options.handwriting_style / handwriting_style when creating an order or previewing.
list_templatesList the authenticated user's saved letter templates.
verify_addressVerify and standardize a US mailing address via USPS. Use before create_order to catch typos and get the USPS-standardized form.
preview_letterRender a preview of a handwritten letter (as an SVG image) and get its price, before creating an order. Does not save anything.
create_orderCreate and pay for a Premier Letters order — a real, handwritten letter mailed via USPS. Requires a Premier Letters API key. Use get_pricing or preview_letter first to confirm the price. For payment, "card_on_file" charges the caller's saved card immediately, "balance" pays from the prepaid account balance (no small-order handling fee; fails with insufficient_balance when short), or "checkout_session" returns a checkout_url for the human to complete payment in a browser. Envelope return address: an explicit no_return_address_ack: true always wins; otherwise a supplied return_address, else the account default. With neither address, set no_return_address_ack: true to send without one.
get_order_statusGet an order's status, delivery/tracking summary, and per-recipient mail status.
list_ordersList the authenticated user's recent orders.
get_balanceGet the authenticated account's prepaid balance (balance_cents) and the top-up rules: minimum and maximum top-up, bonus tiers and suggested amounts. Orders paid with payment.method "balance" skip the small-order handling fee. Use create_topup_link to add funds.
create_topup_linkCreate a Stripe Checkout link that adds prepaid credit (plus any bonus tier) to the authenticated account. Give checkout_url to the human to pay in a browser; the balance updates once they pay (check with get_balance). amount_cents must be a whole number between min_cents and max_cents from get_balance.
More ways to connect
- Zapier (coming soon) — trigger an order from any Zapier automation. Until then, use the REST API or webhooks.
- Shopify — a handwritten thank-you for every paid order. Connect in Settings → Integrations.
- Gmail extension — send a handwritten follow-up from an email thread.
- OpenAPI spec (/openapi.json)
- llms.txt / llms-full.txt
- .well-known/mcp.json
- Webhook settings