Get started
Mail your first recipient by API
Create a key, copy your campaign ID, check your request with a free test, then send it live.
Before you start
- You need a campaign whose audience comes from API / Webhook. You set this in the campaign builder's audience step.
- Only an Owner or Admin on your team can create API keys.
- The campaign must be active before a live request mails anyone. A test request works at any time.
Create a key
- In Postaged, open Settings > API & Webhooks and choose Create API key.
- Give the key a name you'll recognize later, like "CRM sender".
- Leave Access set to Full access. Only a Full access key can send recipients.
- Choose Create API key, then copy the key. We show it only once.
- Store it in an environment variable named
POSTAGED_SEND_KEY. Every Dynamic Audience API sample in these docs reads it from there.
A Full access key mails cards and spends money. Keep it in your own systems, and never give it to an AI assistant. See Authentication and API keys for the other kinds of key.
export POSTAGED_SEND_KEY="<paste your key here>"Copy the campaign ID
Open your campaign, go to its audience step, and open the API / Webhook setup. Copy the Campaign ID. It starts with PA- followed by 6 characters, like PA-4H2K9C.
Every request names the campaign it mails in campaign_id.
{ "campaign_id": "PA-4H2K9C" }Run the in-app test
In the same API / Webhook setup, paste your payload into Request and choose Send test request.
- It runs your payload through the real checks, including address verification, and shows you the response.
- It never claims an address, never charges, and never mails.
- A test accepts up to 10 recipients.
When each result reads the way you expect, you're ready to send live.
{
"campaign_id": "PA-4H2K9C",
"recipients": [
{
"reference": "crm-001",
"first_name": "Dana",
"last_name": "Reyes",
"address_1": "25 Gale Road",
"city": "Bloomfield",
"state": "CT",
"zip": "06002"
}
]
}{
"summary": { "received": 1, "mailed": 1, "notMailed": 0 },
"results": [
{
"reference": "crm-001",
"address": "25 Gale Rd, Bloomfield, CT 06002-2214",
"status": "mailed",
"detail": "Passed your filters. Nothing was sent because this was a test."
}
],
"test": true
}Send live
This request mails real cards
A live request mails every recipient it accepts and charges your team in the same request. Send a test request first.
Send the same payload to POST /api/v1/recipients with curl, Node, or Python.
- We return
200with one result per recipient:mailed, ornot_mailedwith areason. - Any other status listed in Errors means the whole request failed and nothing was mailed.
- A timeout (
504) or a dropped connection may come after some recipients were mailed. Send the same payload again: no one is mailed twice. Within 15 minutes of a request that finished, you get its stored response; otherwise recipients already mailed come back asduplicate_recent. If a request times out, wait 20 minutes, then send it again. Recipients it already mailed come back as duplicates; the rest are mailed once. - Sending the same addresses to the same campaign again within 15 minutes returns the stored response instead of mailing again, even when names or custom fields changed.
curl https://www.postaged.com/api/v1/recipients \
-H "Authorization: Bearer $POSTAGED_SEND_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaign_id": "PA-4H2K9C",
"recipients": [
{
"reference": "crm-001",
"first_name": "Dana",
"last_name": "Reyes",
"address_1": "25 Gale Road",
"city": "Bloomfield",
"state": "CT",
"zip": "06002"
}
]
}'const response = await fetch("https://www.postaged.com/api/v1/recipients", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POSTAGED_SEND_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
campaign_id: "PA-4H2K9C",
recipients: [
{
reference: "crm-001",
first_name: "Dana",
last_name: "Reyes",
address_1: "25 Gale Road",
city: "Bloomfield",
state: "CT",
zip: "06002",
},
],
}),
});
const result = await response.json();
console.log(result);import os
import requests
response = requests.post(
"https://www.postaged.com/api/v1/recipients",
headers={"Authorization": f"Bearer {os.environ['POSTAGED_SEND_KEY']}"},
json={
"campaign_id": "PA-4H2K9C",
"recipients": [
{
"reference": "crm-001",
"first_name": "Dana",
"last_name": "Reyes",
"address_1": "25 Gale Road",
"city": "Bloomfield",
"state": "CT",
"zip": "06002",
},
],
},
timeout=300,
)
print(response.json()){
"summary": { "received": 1, "mailed": 1, "notMailed": 0 },
"results": [
{
"reference": "crm-001",
"address": "25 Gale Rd, Bloomfield, CT 06002-2214",
"status": "mailed",
"detail": "Queued to send.",
"product_type": "Handwritten Card & Handwritten Envelope",
"postage": "first_class",
"mail_by_date": "2026-10-06"
}
]
}Next steps
- Dynamic Audience API reference: every field, response, and error.
- Errors and Rate limits: what to do when a request fails.
- Webhooks: hear about it when someone scans a card's QR code.