Automating Direct Mail
Direct Mail execution produces a production package — a collection of files (rendered PDFs, a printer manifest, an IMb manifest) that commercial printers use to execute physical mail drops.
This guide covers how to programmatically trigger a Direct Mail drop, override print profiles and mail classes per run, and retrieve the finalized artifacts.
Direct Mail Execution Flow
The Direct Mail execution model differs from digital channels in a few key ways:
- Asynchronous Finalization.
POST /schedule-jobsandPOST /campaigns/:id/runsreturn202 Acceptedwithstatus: "finalizing". The broadcast finalizer hydrates the audience, composes the mailpieces, performs IMb encoding, and writes the package to tenant-scoped storage. - Artifact Generation. When the package is
ready, a manifest is generated containing the rendered mailpiece PDF, a printer-readable roster, and IMb data. - Execution State. Direct Mail provides package-level completion states and IMb data, independent of downstream USPS scan-feed events.
Triggering a Drop and Retrieving Artifacts
The following example demonstrates how to trigger a run against a published campaign, poll for the finalized package, and list the generated artifacts.
import os, time, requests
API_KEY = os.environ["EXPERITURE_API_KEY"]
BASE = "https://api.experiture.ai/public/v1"
H = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
CAMPAIGN_ID = "4130bada-9264-465f-bc0c-a26bebcfcc81"
# 1. Trigger a fresh run against the published campaign.
r = requests.post(
f"{BASE}/campaigns/{CAMPAIGN_ID}/runs",
headers={**H, "Idempotency-Key": "2026-q2-spring-recall-001"},
json={
"requestKind": "on_demand", # v1 accepts only on_demand
"metadata": {"orderRef": "PO-44219", "authorizedBy": "ops-ticket-4421"},
"audience": None, # Inherit the campaign's stored targeting
},
)
r.raise_for_status()
run = r.json()["data"]
run_id = run["runId"]
print(f"Queued run {run_id} ({run['status']})")
# 2. Poll for the finalized package.
while True:
runs = requests.get(f"{BASE}/campaigns/{CAMPAIGN_ID}/runs?limit=10", headers=H).json()["data"]["runs"]
current_run = next(r for r in runs if r["runId"] == run_id)
print(f"runStatus={current_run['runStatus']} packageStatus={current_run.get('packageStatus')}")
if current_run.get("packageStatus") in ("ready", "handed_off", "failed", "cancelled"):
break
time.sleep(15)
# 3. Process the artifacts.
if current_run["packageStatus"] in ("ready", "handed_off"):
for art in current_run["package"]["artifacts"]:
print(f" {art['role']:30s} {art['uri']} ({art['piiClassification']})")
else:
print(f"Package failed: {current_run['package'].get('failureKind')} — {current_run['package'].get('lastErrorMessage')}")Key Concepts:
- Idempotency-Key: Ensures that retries do not trigger duplicate physical drops.
- requestKind: In v1 the only accepted value is
on_demand(any other value returns400). Usemetadatato record operational context like the authorizing ticket for a manual drop. - packageStatus: The package status indicates artifact readiness, whereas
runStatustracks the pipeline stage.
Overriding Print and Postal Settings
The POST /campaigns/:id/runs and POST /campaigns/:id/schedule-jobs endpoints accept optional override fields for Direct Mail. Omitted fields default to the tenant's active profile assignment.
Overrides are useful for:
- Printer Routing: Modifying
printProfileIdto use a different tenant-configured print profile. - Postal Contracts: Modifying
postalProfileIdto use a different permit or payment account. - Mail Class Adjustments: Modifying
mailClassfor a specific drop (e.g., overriding a defaultmarketing_mailtofirst_class). - Format Specification: Modifying
productionFormatKeyto enforce a specific layout.
curl -X POST https://api.experiture.ai/public/v1/campaigns/$CID/runs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"requestKind": "on_demand",
"printProfileId": "11111111-1111-1111-1111-111111111111",
"postalProfileId": "22222222-2222-2222-2222-222222222222",
"productionFormatKey": "letter_8.5x11_window_envelope",
"mailClass": "first_class",
"processingCategory": "letter"
}'Accepted Values:
mailClass:first_class,marketing_mail,periodicals,bound_printed_matter,other.processingCategory:letter,flat,card,parcel,other. Must be compatible with the selectedmailClass.productionFormatKey: Canonical layout keys such asletter_8.5x11,postcard_6x11, etc.
Understanding artifactResolutionMode
Controls which version of the rendered artwork is used for the drop:
| Mode | Usage |
|---|---|
latest_live (default) | Utilizes the most recent approved render. |
approved_preparation_set | Pins the drop to a specific, previously-approved render. Requires executionArtifactPreparationSetId. Used for strict compliance scenarios. |
none | Bypasses artifact preparation entirely. Suitable for proof-only validation flows. |
The Package State Machine
A Direct Mail package progresses through several states, reflected in packageStatus:
pending: The run request is queued.assembling: The finalizer is hydrating the audience, rendering pieces, and writing artifacts.ready: All artifacts are successfully written and available.handed_off: The package has been acknowledged by the downstream provider integration.failed: The worker encountered an error.failureKindandlastErrorMessageprovide diagnostic details.cancelled: The package was cancelled administratively before materialization.
Polling Best Practices: A polling interval of 15 to 30 seconds provides timely updates without exceeding rate limits, allowing sufficient time for audience hydration and rendering.
Artifact Schema and Retrieval
When packageStatus is ready, the run object includes a package.artifacts[] array:
{
"artifactId": "art-roster-001",
"role": "printer_manifest_csv",
"uri": "abfss://prod@experiture.dfs.core.windows.net/packages/4130bada/5e5e5e5e/roster.csv",
"contentType": "text/csv",
"rowCount": 17480,
"byteSize": "12482051",
"checksumSha256": "0f6b8...",
"piiClassification": "address",
"metadata": { "addressLayout": "us_legacy_4_line" },
"createdAt": "2026-05-09T13:42:18.000Z"
}Common Artifact Roles:
printer_manifest_csv: The roster file containing recipient data and merged fields required for imposition.mailpiece_pdf_set: The rendered artwork, consolidated or per-piece depending on the print profile.postal_imb_manifest_csv: Intelligent Mail Barcode payloads for tracking.usps_edoc_placeholder: A structured placeholder artifact representing future PostalOne!® submissions.
Accessing the Files
The artifact.uri field provides a tenant-scoped storage path (e.g., abfss://, s3://). It is not a direct, publicly accessible download URL. Retrieve these files using your Experiture-managed compute credentials or via a configured credential broker integration.
If the goal is solely to confirm package generation, the unitCount, checksumSha256, and rowCount fields provide sufficient validation without downloading the payloads.
See Also
- Schedule & Send — API reference for
POST /schedule-jobs - Campaign Runs — API reference for
POST /campaigns/:id/runs - Recurring & Triggered Campaigns — Implementation patterns for automated drops
- Troubleshooting Campaign Delivery — Guidance for handling package and execution failures