PostalForm MCP
Mail real letters from agents: PDF → checkout → status.
PostalForm MCP Developer Docs
PostalForm runs a streamable HTTP MCP server that lets agents create draft mail orders, take payment, and track fulfillment.
UCP (Universal Commerce Protocol)
PostalForm also supports the UCP Checkout capability for platforms that integrate via the UCP MCP binding.
- Discovery profile: https://postalform.com/.well-known/ucp
- UCP MCP endpoint: https://postalform.com/ucp/mcp
- Capability: dev.ucp.shopping.checkout (version 2026-01-11)
- Tools: create_checkout, get_checkout, update_checkout, complete_checkout, cancel_checkout
UCP checkout sessions are dynamically priced based on PDF page count and print options. PostalForm expects the PDF and address data in metadata.postalform (pdf can be { download_url, file_id }, { upload_token }, a data URL, or an allowlisted https URL).
UCP tool calls must include a platform profile in _meta.ucp.profile.
Note: UCP currently supports PDF-based checkouts with Loqate Address IDs (*_address_type="Address") only. For manual addresses, letter text, and workflow forms, use the PostalForm MCP tools on /mcp.
Example UCP create_checkout:
{
"name": "create_checkout",
"arguments": {
"_meta": {
"ucp": {
"profile": "https://platform.example/profiles/v2026-01/shopping-agent.json"
}
},
"currency": "USD",
"line_items": [{ "item": { "id": "postalform_mail_pdf_bw_double" }, "quantity": 1 }],
"payment": {},
"metadata": {
"postalform": {
"pdf": {
"download_url": "https://example.oaiusercontent.com/file.pdf",
"file_id": "file_abc123"
},
"file_name": "letter.pdf",
"sender_name": "Sender Example",
"sender_address_id": "US|LP|Pz0_Qj4_bGJg|16074807|13_ENG",
"sender_address_type": "Address",
"sender_address_text": "123 Sender St, Springfield, IL 62701",
"recipient_name": "Recipient Example",
"recipient_address_id": "US|LP|Pz0_Qj4_bGJg|199825276|99_ENG",
"recipient_address_type": "Address",
"recipient_address_text": "456 Recipient Ave, Springfield, IL 62701",
"double_sided": true,
"color": false
}
}
}
}
Machine payments (x402 private preview)
PostalForm supports x402-based machine payments for direct API order creation.
- Create/pay endpoint:
POST https://postalform.com/api/machine/orders - Validate/quote endpoint (no payment side effects):
POST https://postalform.com/api/machine/orders/validate - Status endpoint:
GET https://postalform.com/api/machine/orders/:id - Flow: unpaid request returns
402+PAYMENT-REQUIRED, client pays and retries withPAYMENT-SIGNATURE, server returns202+PAYMENT-RESPONSE
Required request fields for POST /api/machine/orders:
request_id(UUID)buyer_namebuyer_email(required; set on Stripe PaymentIntent asreceipt_email)pdf(recommended canonical format:{ "upload_token": "..." }; also accepts{ download_url, file_id }, data URL, or allowlisted https URL)- sender/recipient names + addresses (Loqate:
*_address_type="Address"+*_address_id+*_address_text, or Manual:*_address_type="Manual"+*_address_manualwith{ line1, line2?, city, state, zip })
Common options:
double_sided(defaulttrue)color(defaultfalse)mail_class(standard,priority,express)certified(defaultfalse)mailpiece_type(letterorpostcard; defaultletter)postcard_size(4x6,6x9,11x6; required whenmailpiece_type="postcard")
Postcard machine orders use the same endpoints and payment flow. For postcards, send pdf as the final composed postcard PDF and set mailpiece_type: "postcard" plus postcard_size.
Postcard PDF requirements:
- Use a 2-page PDF.
- Page 1 is the artwork side.
- Page 2 is the mailing side. You can place backside artwork or a non-address message there, but do not place sender/recipient names, return or delivery addresses, indicia, or barcode data in the PDF. PostalForm fills the mailing block automatically.
- Match the exact bleed canvas for the selected size. The canonical spec and templates live at postcard PDF guidelines:
PostalForm normalizes postcard print options server-side to standard mail, full color, double-sided, and no certified/signature add-ons.
MCP endpoint
- https://postalform.com/mcp
- Methods: POST/GET/DELETE with the streamable HTTP transport
- Sessions: initialize once, then include the
mcp-session-idheader on all subsequent requests - Auth: no authentication is required today (contact [email protected] for allowlisting)
- Transport: JSON-RPC payloads over POST
Integration quickstart
- Point your MCP client at /mcp and initialize a session.
- Choose addresses: use Loqate IDs via
postalform.search_addresses, or use manual addresses with*_address_type="Manual"+*_address_manual. - Create a draft:
- Letter text:
postalform.create_letter_order_draft(recommended for ChatGPT apps). - Workflow forms:
postalform.list_forms->postalform.get_form_schema->postalform.create_form_order_draft. - PDF upload:
postalform.create_order_draft(ChatGPT file params,upload_token, data URL, or allowlisted https URL).
- Letter text:
- Send the customer to
checkout_url, or usecheckout_sessionfor ChatGPT Instant Checkout. - Poll order status as fulfillment progresses.
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
const transport = new StreamableHTTPClientTransport(new URL('https://postalform.com/mcp'))
const client = new Client({ name: 'my-agent', version: '1.0.0' })
await client.connect(transport)
await client.listTools()
const draft = await client.callTool({
name: 'postalform.create_letter_order_draft',
arguments: {
letter: {
title: 'Demand for payment',
body: 'Hello...\\n\\nThis is my letter body.\\n\\nSincerely,\\n',
signature: 'Sender Example',
},
sender_name: 'Sender Example',
sender_address_type: 'Manual',
sender_address_manual: {
line1: '123 Sender St',
city: 'Springfield',
state: 'IL',
zip: '62701',
},
recipient_name: 'Recipient Example',
recipient_address_type: 'Manual',
recipient_address_manual: {
line1: '456 Recipient Ave',
city: 'Springfield',
state: 'IL',
zip: '62701',
},
},
})
console.log(draft.structuredContent?.checkout_url)
Payment and checkout
External checkout (any MCP client)
- Use
checkout_urlfrompostalform.create_order_draftto send customers to the hosted PostalForm payment page. - Best default for non-ChatGPT MCP clients.
- Open the URL in a browser (or
window.openai.openExternalinside ChatGPT). - Poll
postalform.get_order_statusto confirm payment and fulfillment.
ChatGPT Instant Checkout (Stripe Agentic Commerce)
- PostalForm returns an ACP
checkout_sessionin the draft response that ChatGPT uses to show Instant Checkout. - When the buyer confirms, ChatGPT calls
complete_checkoutwith a Stripe Shared Payment Token (spt_...). - Use
window.openai.requestCheckout(checkout_session)in your UI. - Use
checkout_urlas a fallback ifwindow.openai.requestCheckoutis unavailable.
Tools
postalform.list_forms: List published workflow-based forms available to agents.postalform.get_form_schema: Fetch a workflow schema (fields, dependencies, attachments). May includecheckout_flowmetadata (homeorforms_order) for PostalForm web routing; MCP clients/agents can treat this as informational.postalform.create_letter_order_draft: Create a draft order from letter text (server renders a PDF).postalform.create_form_order_draft: Create a draft order from a workflow form JSON submission (server fills template PDF).postalform.create_pdf_upload: Create a short-lived PDF upload URL +upload_tokenfor agents that cannot pass ChatGPT file params. Upload the PDF, then callpostalform.create_order_draftwithpdf: { upload_token: "..." }.postalform.search_addresses: Search US address suggestions. Input:query(min 3 chars), optionalcontainer(for drilling into Container results), optionaltarget. Output: address suggestions with ids/text/type. If type is Container, call search again withcontainer=idto get Address results for order drafts.postalform.create_order_draft: Create a draft order and receive a checkout URL. Input:pdf(ChatGPT file object{ download_url, file_id }, or{ upload_token }frompostalform.create_pdf_upload, or adata:application/pdf;base64,...URL, or an https URL on an allowlisted host), sender/recipient names, and either Loqate addresses (*_address_type="Address"+*_address_id) or manual addresses (*_address_type="Manual"+*_address_manual). Output:order_id,price_usd,checkout_url,checkout_session.complete_checkout: Finalize a ChatGPT Instant Checkout session with a payment token. Input:checkout_session_id(order*id),buyer(first_name, last_name optional, email),payment_data.token(Stripe shared payment token,spt*...),provider=stripe. Output: checkout session response with status and order permalink.postalform.get_order_status: Fetch the latest order status details. Input:order_id. Output:found,is_paid,current_step(for example:payment_received,receiver_address_verified,sender_address_verified,pdf_normalized,letter_created,email_sent,canceled,refunded,abandoned).postalform.ping: Health check for the MCP server. Input: none. Output: ping payload for connectivity checks.
Tool payload examples
postalform.list_forms
Request:
{
"name": "postalform.list_forms",
"arguments": { "q": "IRS", "limit": 10 }
}
postalform.get_form_schema
Request:
{
"name": "postalform.get_form_schema",
"arguments": { "slug": "8822" }
}
Note: the response may include checkout_flow. This is workflow metadata for PostalForm web checkout routing and does not change MCP tool-call sequencing.
postalform.search_addresses
Request:
{
"name": "postalform.search_addresses",
"arguments": {
"target": "recipient",
"query": "123 Main St"
}
}
Response:
{
"structuredContent": {
"view": "address_suggestions",
"target": "recipient",
"query": "123 Main St",
"suggestions": [
{
"id": "US|LP|Pz0_Qj4_bGJg|16074807|13_ENG",
"text": "123 Main St, Springfield, IL 62701",
"type": "Address",
"description": ""
}
]
}
}
postalform.create_letter_order_draft
Request:
{
"name": "postalform.create_letter_order_draft",
"arguments": {
"request_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"letter": {
"title": "Payment demand letter",
"body": "Hello,\\n\\nThis is the letter body.\\n\\nSincerely,\\n",
"signature": "Sender Example"
},
"sender_name": "Sender Example",
"sender_address_type": "Manual",
"sender_address_manual": {
"line1": "123 Sender St",
"city": "Springfield",
"state": "IL",
"zip": "62701"
},
"recipient_name": "Recipient Example",
"recipient_address_type": "Manual",
"recipient_address_manual": {
"line1": "456 Recipient Ave",
"city": "Springfield",
"state": "IL",
"zip": "62701"
}
}
}
postalform.create_form_order_draft
Request:
{
"name": "postalform.create_form_order_draft",
"arguments": {
"request_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"slug": "8822",
"fields": {
"name_line_1": "Sender Example",
"old_address_line_1": "123 Old St",
"old_city": "Springfield",
"old_state": "IL",
"old_zip": "62701",
"new_address_line_1": "456 New Ave",
"new_city": "Springfield",
"new_state": "IL",
"new_zip": "62701"
},
"sender_name": "Sender Example",
"sender_address_type": "Address",
"sender_address_id": "US|LP|Pz0_Qj4_bGJg|16074807|13_ENG",
"sender_address_text": "123 Sender St, Springfield, IL 62701",
"recipient_name": "IRS",
"recipient_address_type": "Manual",
"recipient_address_manual": {
"line1": "Internal Revenue Service",
"city": "Kansas City",
"state": "MO",
"zip": "64999"
},
"use_workflow_recipient": false
}
}
postalform.create_pdf_upload
Request:
{
"name": "postalform.create_pdf_upload",
"arguments": {
"file_name": "letter.pdf",
"content_type": "application/pdf",
"content_length": 1234567
}
}
Response:
{
"structuredContent": {
"upload_url": "https://postalform.com/api/mcp/pdf-uploads/pfu_...",
"upload_token": "pfu_...",
"expires_at": "2026-01-17T12:00:00Z",
"max_bytes": 104857600,
"required_headers": {
"Content-Type": "multipart/form-data"
}
}
}
Upload the PDF with multipart/form-data using the file field (aliases pdf and pdfFile are also accepted), then pass upload_token to postalform.create_order_draft.
postalform.create_order_draft
Note: pdf accepts a ChatGPT file object, an upload_token, or a base64 data URL (data:application/pdf;base64,...). If you pass a URL, it must be https and hosted on an allowlisted domain (default: *.oaiusercontent.com).
Request:
{
"name": "postalform.create_order_draft",
"arguments": {
"request_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"pdf": { "upload_token": "pfu_..." },
"file_name": "letter.pdf",
"sender_name": "Sender Example",
"sender_address_id": "US|LP|Pz0_Qj4_bGJg|16074807|13_ENG",
"sender_address_type": "Address",
"sender_address_text": "123 Sender St, Springfield, IL 62701",
"recipient_name": "Recipient Example",
"recipient_address_id": "US|LP|Pz0_Qj4_bGJg|199825276|99_ENG",
"recipient_address_type": "Address",
"recipient_address_text": "456 Recipient Ave, Springfield, IL 62701",
"double_sided": true,
"color": false
}
}
Response:
{
"structuredContent": {
"view": "order_draft",
"order_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"page_count": 2,
"price_usd": 2.99,
"checkout_url": "https://postalform.com/payment?orderId=8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"sender_name": "Sender Example",
"sender_address_text": "123 Sender St, Springfield, IL 62701",
"recipient_name": "Recipient Example",
"recipient_address_text": "456 Recipient Ave, Springfield, IL 62701",
"checkout_session": {
"id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"payment_provider": {
"provider": "stripe",
"merchant_id": "profile_123",
"supported_payment_methods": ["card", "apple_pay", "google_pay"]
},
"status": "ready_for_payment",
"currency": "usd",
"line_items": [
{
"id": "line_item_8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"item": { "id": "postalform_mail_pdf", "quantity": 1 },
"base_amount": 299,
"discount": 0,
"subtotal": 299,
"tax": 0,
"total": 299
}
],
"totals": [
{ "type": "items_base_amount", "display_text": "Items", "amount": 299 },
{ "type": "subtotal", "display_text": "Subtotal", "amount": 299 },
{ "type": "tax", "display_text": "Tax", "amount": 0 },
{ "type": "total", "display_text": "Total", "amount": 299 }
],
"links": [
{ "type": "terms_of_use", "value": "https://postalform.com/terms" },
{ "type": "privacy_policy", "value": "https://postalform.com/privacy" }
],
"payment_mode": "test"
}
}
}
complete_checkout
Request:
{
"name": "complete_checkout",
"arguments": {
"checkout_session_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"buyer": {
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]"
},
"payment_data": {
"token": "spt_test_123",
"provider": "stripe"
}
}
}
Response:
{
"structuredContent": {
"id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"buyer": {
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]"
},
"status": "completed",
"currency": "usd",
"line_items": [
{
"id": "line_item_8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"item": { "id": "postalform_mail_pdf", "quantity": 1 },
"base_amount": 299,
"discount": 0,
"subtotal": 299,
"tax": 0,
"total": 299
}
],
"fulfillment_options": [
{
"type": "shipping",
"id": "postalform_standard",
"title": "First Class mail",
"subtitle": "USPS First Class",
"carrier": "USPS",
"carrier_info": "USPS",
"earliest_delivery_time": "2025-01-01T00:00:00.000Z",
"latest_delivery_time": "2025-01-06T00:00:00.000Z",
"subtotal": 0,
"tax": 0,
"total": 0
}
],
"fulfillment_option_id": "postalform_standard",
"totals": [
{ "type": "items_base_amount", "display_text": "Items", "amount": 299 },
{ "type": "subtotal", "display_text": "Subtotal", "amount": 299 },
{ "type": "tax", "display_text": "Tax", "amount": 0 },
{ "type": "total", "display_text": "Total", "amount": 299 }
],
"order": {
"id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"checkout_session_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"permalink_url": "https://postalform.com/order/complete?order_id=8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b"
},
"messages": [],
"links": [
{ "type": "terms_of_use", "value": "https://postalform.com/terms" },
{ "type": "privacy_policy", "value": "https://postalform.com/privacy" }
]
}
}
postalform.get_order_status
Response:
{
"structuredContent": {
"view": "order_status",
"found": true,
"order_id": "8c1a1b58-2c8f-4f4f-9c46-2c1ac32d7a1b",
"is_paid": true,
"current_step": "letter_created"
}
}
Error response example
{
"isError": true,
"content": [
{
"type": "text",
"text": "recipient_address_manual is required when recipient_address_type is Manual."
}
]
}
Integration notes
- Idempotency: use
request_idon draft creation tools (postalform.create_order_draft,postalform.create_letter_order_draft,postalform.create_form_order_draft) and reuse the same value on retries. The server will return the existing draft. - Errors: tool calls that fail validation return
isError=truewith a human-readable message. For Instant Checkout,complete_checkoutcan also return ACP messages with error codes likepayment_declinedorrequires_3ds. - Instant Checkout fallback: if
window.openai.requestCheckoutis unavailable orcheckout_session.payment_providerlacksmerchant_id, usecheckout_urlinstead. - Order status steps:
payment_received,receiver_address_verified,sender_address_verified,pdf_normalized,letter_created,email_sent,canceled,refunded,abandoned.
Limits and requirements
- All orders are printed from PDFs. For
postalform.create_order_draftyou supply the PDF. Forpostalform.create_letter_order_draftandpostalform.create_form_order_draftPostalForm generates the PDF server-side. PDFs are sanitized before printing. - Max 199 pages and 100 MB per file.
download_urlmust be HTTPS and hosted on an allowlisted domain (ChatGPT attachments useoaiusercontent.comby default). The URL must be publicly reachable without auth headers. If you cannot provide an allowlisted URL, usepostalform.create_pdf_uploadto get anupload_token, or pass adata:application/pdf;base64,...URL instead.- US addresses only. Use Loqate address ids returned by
postalform.search_addresses, or use manual address input with*_address_type="Manual"and*_address_manual. - Address suggestions can include
type="Container"(buildings/complexes). Callpostalform.search_addressesagain withcontainer=<id>and a refined query (suite, unit, PO Box) to gettype="Address"results. Onlytype="Address"(not Container) is valid for Loqate-based order drafts.
Related Servers
Twenty CRM
Interact with the Twenty CRM API through chat-based tools.
Canvas MCP Server
An MCP server for Canvas LMS, providing full functionality for both students and instructors.
DeepWriter
Interact with the DeepWriter API, an AI-powered writing assistant.
Tovee.AI
Connect the apps that make you, you
Avocado AI
Collaborative AI creative workspace for agencies and ecommerce teams to generate on-brand images, videos, and ad creative at scale.
Instagit
Let your agents instantly understand any GitHub repo
GroundMemory
Persistent identity and memory across AI tools - mcp-native, local-first, framework-agnostic, production-ready.
TickTick
Manage tasks, projects, and habits using the TickTick API.
MCP Outlook Tools
Interact with Microsoft Outlook for calendar management, email operations, and search functionality.
Spotify
Control your Spotify music playback through conversations using the Spotify API.