PostalForm Projects API Reference
Use this Cloudflare-hosted API for Stripe Projects-style provisioning, PDF uploads, quotes, test sends, live sends, credits, and signed customer webhooks.
Base URLs
Dashboard: https://projects.postalform.com
API: https://projects.postalform.com/api/v1
Authentication
Authorization: Bearer pf_test_...
Authorization: Bearer pf_live_...
Typical test flow
POST /api/v1/documents/upload-intent
PUT {upload_url}
POST /api/v1/documents/{document_id}/complete
POST /api/v1/letters/quotes
POST /api/v1/letters
GET /api/v1/letters/{order_id}
GET /api/v1/letters/{order_id}/document.pdf
Core Request Parameters
POST /api/v1/documents/upload-intent
{
"content_type": "application/pdf",
"byte_size": 123456,
"page_count": 4
}
POST /api/v1/letters/quotes
{
"document_id": "doc_...",
"mail_class": "usps_first_class",
"color": false,
"double_sided": true,
"certified": false,
"destination_country_code": "US",
"origin_country_code": "US"
}
POST /api/v1/letters
Idempotency-Key: unique-order-key
{
"quote_id": "quote_...",
"recipient": { "name": "...", "line1": "...", "city": "...", "postal_code": "...", "countryCode": "US" },
"sender": { "name": "...", "line1": "...", "city": "...", "postal_code": "...", "countryCode": "US" },
"metadata": { "customer_id": "..." }
}
Provider routing is automatic. Public API clients should not send provider_strategy; unsupported provider overrides are rejected.
Projects uses developer-infrastructure pricing separate from the public PostalForm.com one-off workflow pricing. Standard letters start with a $1.80 base fee plus $0.20 per billable black-and-white page or $0.40 per billable color page. U.S./Canada Priority/Express stays on Click2Mail cost-plus pricing, proof-mail add-ons remain $8.00 for U.S. Certified Mail plus $3.00 for Electronic Return Receipt, and PostGrid fallback mail from Canada to the Netherlands includes a sheet-count postage guard when PinGen cannot accept the letter.
International Mailing
Letter quotes accept destination_country_code and origin_country_code; both default to US. Supported destination countries are US, CA, AT, BE, CH, DE, FR, GB, IN, LU, and NL.
U.S. and Canada letters prefer Lob when eligible. U.S./Canada Priority/Express letters route through Click2Mail. Supported non-U.S./Canada standard letters can route through PinGen cheap for local print when PinGen credentials are configured and the PDF fits PinGen's 8 MB and destination page limits. International Express routes through PinGen Fast for AT, CH, DE, GB, IN, and NL with a $4 surcharge; it is unavailable for destinations without a distinct PinGen Fast product. Ineligible standard letters fall back to PostGrid where available.
Postcards require a composed two-page PDF and do not support certified or registered mail. Lob-routed international postcards must be 4x6 and use a U.S. sender return address; larger international postcards or non-U.S. return addresses route to PostGrid where available.
Proof Mail
For U.S. standard letters, certified=true requests USPS Certified Mail through Lob when the piece fits Lob limits. For Belgium, Switzerland, and France standard letters, certified=true requests PinGen registered mail when the piece fits PinGen limits. Postcards do not support certified or registered mail.
Credits And Webhooks
Use /api/v1/credits/balance, /api/v1/credits/checkout-session, /api/v1/credits/payment-methods/setup-session, and /api/v1/credits/auto-refill for prepaid live-mail credits and automatic refill setup. Use /api/v1/webhook-endpoints and /api/v1/webhook-events/:id/replay for signed customer status webhooks.
Customer webhook events are emitted for provider status changes only, with postalform.{letter|postcard}.{status} event names: accepted_by_provider, in_transit, delivered, returned, failed, and canceled. Internal timeline states such as queued, document_preparing, document_prepared, submitted_to_provider, and submission_pending are visible on order reads but are not customer webhooks.
PostalForm-Signature: t=1777592400,v1=<hmac_sha256_hex>
{
"id": "evt_123",
"type": "postalform.letter.in_transit",
"data": {
"object": {
"id": "ord_123",
"object": "letter",
"status": "in_transit",
"mode": "live",
"price_cents": 2012,
"currency": "usd",
"funds_status": "captured",
"billing_rail": "prepaid_credits",
"selected_provider": "click2mail",
"metadata": {}
}
},
"provider": {
"name": "click2mail",
"provider_letter_id": "c2m_123",
"status_raw": "MAILED",
"status_normalized": "in_transit",
"tracking_number": "9405500000000000000001",
"tracking_status": "In Transit"
}
}