Build with Postcard.bot
Let AI agents send real physical postcards worldwide. Integrate via MCP server or REST API.
Get an API key
Sign up at postcard.bot, go to your account page, and generate an API key in the API Keys tab.
Add balance
Add credits via postcard.bot/buy-credits or the POST /api/v1/credits endpoint. Prepaid balance — funds must be available before sending. Volume pricing from $0.69/postcard.
Configure your MCP client
Add the MCP server to Claude Desktop, Claude Code, or any MCP-compatible client.
The fastest way to get started. No API key needed, no local install — OAuth handles authentication automatically. Works with Claude Desktop, Claude Code, ChatGPT, and any MCP client that supports remote servers.
https://postcard.bot/api/mcpClaude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"postcardbot": {
"url": "https://postcard.bot/api/mcp"
}
}
}Claude Code
claude mcp add --transport http postcardbot https://postcard.bot/api/mcpHow it works
- Add the URL to your MCP client
- Your client opens a browser window for you to sign in
- Sign in with Google or email (same Postcard.bot account)
- Click "Allow" to authorize access
- Start sending postcards — your balance and pricing tier apply automatically
Install via npm
npx -y @postcardbot/mcp-serverClaude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"postcardbot": {
"command": "npx",
"args": ["-y", "@postcardbot/mcp-server"],
"env": {
"POSTCARDBOT_API_KEY": "pk_live_your_key_here"
}
}
}
}Claude Code
claude mcp add postcardbot -- npx -y @postcardbot/mcp-serverThen set POSTCARDBOT_API_KEY in your shell environment.
send_postcard
Send a physical postcard. Cards are printed and shipped within 24 hours. Delivery takes 5-10 business days.
Parameters:
to— Recipient address (name,address_line1,cityrequired;address_line2,state,zip,countryoptional)from— Sender/return address (same fields)message— Back-of-card message (max 350 characters)image_url— Front image URL (publicly accessible, min 1875x1275px recommended)
Example prompt:
bulk_send
Send the same postcard to multiple recipients (async). Up to 5,000 recipients per request. Cards are processed in background batches (~25/minute).
Parameters:
recipients— Array of recipient addresses (max 5,000, same fields asto)from— Sender/return address (same for all postcards)message— Back-of-card message (max 350 characters)image_url— Front image URL (publicly accessible, min 1875x1275px recommended)
Example prompt:
Returns a bulk_id immediately. Total cost is reserved upfront. Failed cards are automatically refunded. Poll status_url for progress.
check_balance
Check account balance, total postcards sent, and current volume pricing tier. Use this before sending to know your per-postcard cost.
get_pricing
Get all volume pricing tiers. No parameters required.
check_status
Check delivery status of a previously sent postcard.
Parameters:
postcard_id— The ID returned fromsend_postcard
create_webhook
Register a URL to receive real-time postcard event notifications. Events are signed with HMAC-SHA256. Max 10 webhooks per account.
Parameters:
url— HTTPS URL to receive webhook POST requestsevents— Event types:postcard.sent,postcard.delivered,postcard.failed,postcard.returned
The signing secret is returned only on creation — save it securely.
list_webhooks
delete_webhook
List all registered webhooks or delete one by its webhook_id.
All API requests require authentication via Bearer token. Include your API key in the Authorization header.
Authorization: Bearer pk_live_your_key_here/api/v1/postcardsSend a postcard
{
"to": {
"name": "Jane Doe",
"address_line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"country": "US"
},
"from": {
"name": "John Smith",
"address_line1": "456 Oak Ave",
"city": "New York",
"state": "NY",
"zip": "10001",
"country": "US"
},
"message": "Wish you were here!",
"image_url": "https://example.com/golden-gate.jpg"
}{
"id": "pc_abc123",
"status": "sent",
"service": "lob",
"expected_delivery_date": "2025-03-15",
"price": 1.99,
"balance_remaining": 18.01
}/api/v1/postcards/bulkSend postcards to multiple recipients — async (up to 5,000)
{
"recipients": [
{ "name": "Jane Doe", "address_line1": "123 Main St", "city": "San Francisco", "state": "CA", "zip": "94102", "country": "US" },
{ "name": "John Smith", "address_line1": "456 Oak Ave", "city": "New York", "state": "NY", "zip": "10001", "country": "US" }
],
"from": { "name": "Acme Inc", "address_line1": "789 Pine Rd", "city": "Austin", "state": "TX", "zip": "78701", "country": "US" },
"message": "Happy holidays from Acme!",
"image_url": "https://example.com/holiday-card.jpg"
}{
"bulk_id": "bulk_1710000000_abc123",
"status": "queued",
"total": 2,
"total_cost": 3.98,
"status_url": "https://postcard.bot/api/v1/postcards/bulk/bulk_1710000000_abc123",
"message": "Job queued. 2 postcards will be processed shortly. Poll status_url for progress."
}Cost is reserved upfront. Cards are processed in background batches (~25/minute). Failed cards are automatically refunded. Poll status_url to check progress.
/api/v1/postcards/bulk/:bulk_idCheck bulk job progress
{
"bulk_id": "bulk_1710000000_abc123",
"status": "completed",
"total": 500,
"processed": 500,
"succeeded": 498,
"failed": 2,
"total_cost": 492.02,
"created_at": "2026-03-10T12:00:00Z",
"completed_at": "2026-03-10T12:20:00Z",
"postcard_ids": ["pc_abc1", "pc_abc2", "..."],
"failures": [
{ "index": 42, "to": "Bad Address, Nowhere", "error": "Invalid address" }
]
}/api/v1/balanceCheck account balance and current pricing tier
{
"balance": 47.50,
"currency": "USD",
"lifetime_top_up": 150.00,
"tier": { "number": 3, "name": "Silver" },
"current_pricing": {
"usa": 1.29,
"international": 2.29
},
"top_up_url": "https://postcard.bot/buy-credits"
}/api/v1/creditsAdd credits via Stripe checkout (min $5, max $10,000)
{
"amount": 50.00
}{
"checkout_url": "https://checkout.stripe.com/...",
"amount": 50.00,
"currency": "USD"
}/api/v1/postcards/:idCheck postcard status
{
"id": "pc_abc123",
"status": "sent",
"delivery_status": "in_transit",
"service": "lob",
"expected_delivery_date": "2025-03-15",
"to": {
"name": "Jane Doe",
"city": "San Francisco",
"country": "US"
},
"created_at": "2025-03-10T12:00:00Z",
"sent_at": "2025-03-10T12:01:00Z"
}/api/v1/pricingGet pricing tiers (no authentication required)
{
"postcards": {
"usa": { "price": 1.99, "currency": "USD" },
"international": { "price": 2.99, "currency": "USD" }
},
"volume_tiers": [
{ "tier": 1, "name": "Starter", "min_top_up": 1, "max_top_up": 19, "usa_price": 1.49, "international_price": 2.49 },
{ "tier": 2, "name": "Bronze", "min_top_up": 20, "max_top_up": 49, "usa_price": 1.29, "international_price": 2.29 },
{ "tier": 3, "name": "Silver", "min_top_up": 50, "max_top_up": 199, "usa_price": 0.99, "international_price": 1.99 },
{ "tier": 4, "name": "Gold", "min_top_up": 200, "max_top_up": 499, "usa_price": 0.85, "international_price": 1.85 },
{ "tier": 5, "name": "Platinum", "min_top_up": 500, "max_top_up": 999, "usa_price": 0.79, "international_price": 1.79 },
{ "tier": 6, "name": "Diamond", "min_top_up": 1000, "max_top_up": null, "usa_price": 0.69, "international_price": 1.69 }
]
}/api/v1/webhooksRegister a webhook URL for postcard event notifications. Max 10 per account. HTTPS only.
{
"url": "https://example.com/webhooks/postcards",
"events": ["postcard.created", "postcard.sent", "postcard.delivered", "postcard.failed", "postcard.returned"]
}{
"id": "wh_abc123",
"url": "https://example.com/webhooks/postcards",
"events": ["postcard.created", "postcard.sent", "postcard.delivered", "postcard.failed", "postcard.returned"],
"secret": "whsec_...",
"active": true,
"created_at": "2026-03-09T12:00:00Z"
}The secret is only returned on creation. Save it securely — use it to verify webhook signatures via HMAC-SHA256 in the X-PostcardBot-Signature header.
/api/v1/webhooksList all webhooks for your account
{
"webhooks": [
{
"id": "wh_abc123",
"url": "https://example.com/webhooks/postcards",
"events": ["postcard.sent", "postcard.delivered"],
"active": true,
"created_at": "2026-03-09T12:00:00Z"
}
]
}/api/v1/webhooks/:idUpdate a webhook (URL, events, or active status)
{
"url": "https://example.com/new-endpoint",
"events": ["postcard.sent"],
"active": false
}/api/v1/webhooks/:idDelete a webhook
Webhook Payload
Events are sent as POST requests with HMAC-SHA256 signature in the X-PostcardBot-Signature header (format: t=timestamp,v1=base64signature).
{
"event": "postcard.sent",
"postcard_id": "pc_abc123",
"status": "sent",
"to": {
"name": "Jane Doe",
"city": "San Francisco",
"country": "US"
},
"timestamp": "2026-03-09T12:01:00Z"
}Webhooks that return 410 Gone are automatically deactivated.
Error Responses
Unauthorized
Missing or invalid API key
Insufficient balance
Top up at postcard.bot/buy-credits
Validation error
Missing or invalid fields (details in response body)
curl
curl -X POST https://postcard.bot/api/v1/postcards \
-H "Authorization: Bearer pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"to": {
"name": "Jane Doe",
"address_line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"country": "US"
},
"from": {
"name": "John Smith",
"address_line1": "456 Oak Ave",
"city": "New York",
"state": "NY",
"zip": "10001"
},
"message": "Wish you were here!",
"image_url": "https://example.com/photo.jpg"
}'Python
import requests
response = requests.post(
"https://postcard.bot/api/v1/postcards",
headers={"Authorization": "Bearer pk_live_your_key_here"},
json={
"to": {
"name": "Jane Doe",
"address_line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"country": "US",
},
"from": {
"name": "John Smith",
"address_line1": "456 Oak Ave",
"city": "New York",
"state": "NY",
"zip": "10001",
},
"message": "Wish you were here!",
"image_url": "https://example.com/photo.jpg",
},
)
result = response.json()
print(f"Postcard {result['id']} sent! Delivery: {result['expected_delivery_date']}")Node.js / TypeScript
const response = await fetch("https://postcard.bot/api/v1/postcards", {
method: "POST",
headers: {
"Authorization": "Bearer pk_live_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: {
name: "Jane Doe",
address_line1: "123 Main St",
city: "San Francisco",
state: "CA",
zip: "94102",
country: "US",
},
from: {
name: "John Smith",
address_line1: "456 Oak Ave",
city: "New York",
state: "NY",
zip: "10001",
},
message: "Wish you were here!",
image_url: "https://example.com/photo.jpg",
}),
});
const result = await response.json();
console.log(`Postcard ${result.id} sent! Delivery: ${result.expected_delivery_date}`);Full API spec available at /api/v1/openapi (OpenAPI 3.0 JSON). Import into Postman, Swagger UI, or any API client.
| Tier | Lifetime top-up | USA | International |
|---|---|---|---|
| Pay-as-you-go | $0 | $1.99 | $2.99 |
| Starter | $1–$19 | $1.49 | $2.49 |
| Bronze | $20–$49 | $1.29 | $2.29 |
| Silver | $50–$199 | $0.99 | $1.99 |
| Gold | $200–$499 | $0.85 | $1.85 |
| Platinum | $500–$999 | $0.79 | $1.79 |
| Diamond | $1,000+ | $0.69 | $1.69 |
Pricing is based on your lifetime top-up amount. Your tier upgrades automatically as you add more credits. Prepaid balance required — add credits via postcard.bot/buy-credits or the API. Auto-recharge coming soon.
| Variable | Required | Description |
|---|---|---|
POSTCARDBOT_API_KEY | Yes | Your API key from postcard.bot/account |
POSTCARDBOT_API_URL | No | Override API base URL (default: https://postcard.bot) |