Print and Mail API: Send Documents Programmatically in 3 API Calls
Automate document mailing with the Corvo print and mail API. Upload a PDF, get carrier rates, and ship via USPS, FedEx, or UPS — all in three REST API calls.
If your application generates documents that need to be physically mailed — demand letters, eviction notices, compliance filings, legal marketing campaigns — you have two options. You can build and manage a mailroom operation, or you can make three API calls and let someone else handle the printing, packaging, and shipping.
This post walks through how the Corvo API works, with real endpoint paths and request shapes you can copy into your codebase today.
Why Automate Document Mailing?
Manual mailing doesn't scale. When your system generates a demand letter because an account hit 90 days past due, someone still has to print it, stuff it in an envelope, buy postage, and drop it at the post office. That workflow breaks at volume, introduces delays, and creates compliance risk when documents don't go out on time.
A print and mail API eliminates that bottleneck. Your application triggers the mailing programmatically — same as it would send an email or fire a webhook. The document goes from PDF to shipped package without anyone touching a printer.
The 3-Call Flow
Every shipment through the Corvo API follows three steps:
- Upload your PDF document
- Create a shipment (get rate quotes from USPS, FedEx, and UPS)
- Buy the shipment (select a rate, charge your account, and ship)
Let's walk through each one.
Step 1: Upload the Document
Upload the PDF you want to print and mail. The API returns a document_key that you'll reference when creating the shipment.
curl -X POST https://corvo.to/api/v1/documents/upload \
-H "Authorization: Bearer sk_test_9f8a7b6c5d4e3f2a1b0c" \
-F file=@demand-letter.pdf
Response:
{
"data": {
"document_key": "documents/a3b8c1d2-e4f5-6789-abcd-ef0123456789/demand-letter.pdf",
"filename": "demand-letter.pdf",
"page_count": 3,
"size_bytes": 102400
}
}
The page_count is detected automatically and used to calculate printing costs. You can also skip this step entirely by passing a base64-encoded PDF or a public URL directly in the create shipment request — useful when you're generating documents on the fly.
Step 2: Create a Shipment
Create the shipment by providing the document key, recipient address, return address, and print options. When you omit carrier and service, the API returns rate quotes from all available carriers so you can choose.
curl -X POST https://corvo.to/api/v1/shipments \
-H "Authorization: Bearer sk_test_9f8a7b6c5d4e3f2a1b0c" \
-H "Content-Type: application/json" \
-d '{
"document_key": "documents/a3b8c1d2-e4f5-6789-abcd-ef0123456789/demand-letter.pdf",
"shipment_name": "Demand Letter - Acct #4821",
"to_address": {
"name": "John Doe",
"street1": "123 Main St",
"street2": "Suite 100",
"city": "New York",
"state": "NY",
"zip": "10001"
},
"from_address": {
"name": "Collections Dept",
"company": "Apex Recovery LLC",
"street1": "456 Oak Ave",
"city": "Charlotte",
"state": "NC",
"zip": "28202"
},
"print_options": {
"color": false,
"duplex": false
}
}'
The response comes back with a draft shipment and an array of rate quotes:
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "draft",
"rates": [
{
"quote_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"carrier": "USPS",
"service": "First",
"total_cents": 840,
"delivery_days": 5,
"delivery_date_guaranteed": false
},
{
"quote_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"carrier": "FedEx",
"service": "FEDEX_GROUND",
"total_cents": 1249,
"delivery_days": 3,
"delivery_date_guaranteed": false
},
{
"quote_id": "c3d4e5f6-a7b8-9012-cdef-012345678901",
"carrier": "UPS",
"service": "Ground",
"total_cents": 1330,
"delivery_days": 3,
"delivery_date_guaranteed": false
}
],
"quotes_expire_at": "2026-02-18T12:30:00.000Z"
}
}
Each rate includes a quote_id, the carrier, service level, total cost in cents, and estimated delivery days. The total_cents is all-inclusive — printing, handling, and postage.
Addresses are verified automatically on creation. If an address can't be validated, the API returns an error before you spend anything.
Step 3: Buy the Shipment
Pick a rate and purchase. Pass the quote_id of the rate you want:
curl -X POST https://corvo.to/api/v1/shipments/f47ac10b-58cc-4372-a567-0e02b2c3d479/buy \
-H "Authorization: Bearer sk_test_9f8a7b6c5d4e3f2a1b0c" \
-H "Content-Type: application/json" \
-d '{"quote_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}'
Response:
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "queued",
"carrier": "USPS",
"service": "First",
"tracking_number": "9400111899223100012345",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223100012345",
"total_charged_cents": 840
}
}
The shipment moves to queued, your card on file is charged, and Corvo handles the rest: printing, packaging, label generation, and carrier handoff. You get a tracking number and URL immediately.
That's the complete flow. Three calls: upload, create, buy.
Authentication
Every request requires an API key passed as a Bearer token in the Authorization header. Keys are scoped to your organization — all shipments created with a key belong to that org.
Corvo uses two key prefixes:
sk_test_-- Test keys for development and staging. Shipments are validated but never printed or shipped.sk_live_-- Live keys for production. Shipments are printed, charged to your card, and delivered to real addresses.
Test and live environments are completely separate. Create API keys in Settings > API Keys in the Corvo dashboard.
Narrowing the Draft Quotes
If you already know which carrier and service you want, pass carrier and service in shipping_options to filter the draft quotes that come back from the create step. That helps your worker avoid comparing options it will never use, but it does not skip the explicit buy step:
curl -X POST https://corvo.to/api/v1/shipments \
-H "Authorization: Bearer sk_test_9f8a7b6c5d4e3f2a1b0c" \
-H "Content-Type: application/json" \
-d '{
"document_key": "documents/a3b8c1d2-e4f5-6789-abcd-ef0123456789/demand-letter.pdf",
"to_address": {
"name": "John Doe",
"street1": "123 Main St",
"city": "New York",
"state": "NY",
"zip": "10001"
},
"print_options": { "color": false, "duplex": false },
"shipping_options": {
"carrier": "USPS",
"service": "First"
}
}'
The response still comes back as a draft, and you still buy the shipment in a separate call with the matching quote_id. If you're generating PDFs on the fly, you can inline the document as base64 or pass a URL and skip the upload call, but the shipment contract remains draft first, then buy.
Certified Mail via API
For documents that require proof of mailing and delivery — demand letters, eviction notices, IRS filings — set certified_mail and return_receipt in the shipping options:
{
"shipping_options": {
"certified_mail": true,
"return_receipt": true
}
}
Corvo handles the USPS Certified Mail forms and postage automatically, and can request USPS Return Receipt service when you set return_receipt: true. You get a tracking number immediately plus carrier events, mailing_records, artifacts, and Corvo-generated mailing summaries as the shipment progresses.
Carrier Options
All three major carriers are available through the same API — no separate integrations, no different request formats:
- USPS -- First Class, Priority Mail, Certified Mail with optional Return Receipt service
- FedEx -- Ground, Express, Overnight
- UPS -- Ground, 2nd Day Air, Next Day Air
The API rate-shops across all carriers and returns quotes sorted by price and delivery time. You pick the one that fits your timeline and budget, or lock in a specific carrier and service for automated workflows.
High-Volume Sequential API Workflow
When you need to send hundreds of documents at once, use a queue worker that creates and buys shipments sequentially:
for shipment in queue:
# 1) POST /api/v1/shipments
# 2) choose quote_id
# 3) POST /api/v1/shipments/{id}/buy
# 4) store tracking + status
# 5) retry failures with backoff
Each shipment is processed independently by your queue worker. A failure on one item does not block the rest:
{
"queue_summary": {
"total": 500,
"succeeded": 492,
"failed": 8
},
"failed_ids": ["acct_4822", "acct_4921"]
}
For a collection agency processing 500 accounts on the first of the month, this model gives fine-grained retry control and clean audit logs per shipment.
Real-World Use Cases
Here's how teams are wiring the Corvo API into their existing systems:
Collection agencies: automatic demand letters. When your collections software marks an account as 90 days past due, a webhook fires. Your integration generates the demand letter PDF, uploads it to Corvo, and sends it via USPS Certified Mail with Return Receipt service. The tracking number, mailing-record summary, and delivery milestones feed back into the account record. No human touches the process.
Property management: eviction notice runs. Your PM software identifies tenants who haven't paid by the 5th. A nightly job generates notice PDFs, uploads them, and creates shipments sequentially with USPS Certified Mail. Operations gets a dashboard of tracking statuses the next morning.
Legal marketing: court-filing-triggered campaigns. Your system monitors new court filings — DUI charges, personal injury cases, bankruptcy petitions. When a filing matches your criteria, it generates a solicitation letter with the case details, uploads the PDF, and ships it via USPS First Class. Hundreds of letters go out daily without a manual step.
Tax professionals: IRS certified mailings. During tax season, CPAs often use Certified Mail to preserve stronger USPS mailing records for time-sensitive filings. Instead of 50 trips to the post office in April, the firm's software sends each filing through the API with certified_mail: true and keeps carrier events, mailing summaries, and evidence exports in one place.
Pricing
Corvo charges per shipment with no monthly fees, no minimums, and no contracts. Each shipment cost breaks down into:
- Handling fee -- per-shipment charge for printing and packaging
- Printing -- per-page charge (black and white or color)
- Postage -- carrier rate, shopped across USPS, FedEx, and UPS
The total_cents field in each rate quote is the all-in price. What you see in the quote is what gets charged.
Getting Started
- Sign up at corvo.to/signup and add a payment method
- Create an API key in Settings > API Keys (you'll get an
sk_test_key for development) - Send a test shipment using the three-call flow above — test keys validate everything but never print or charge
The full API reference — including all endpoint parameters, response shapes, error codes, and the sequential API workflow — is at corvo.to/api-docs.
Ready to automate your document mailing? Sign up for Corvo and send your first shipment in minutes. Or explore the full API documentation to plan your integration.
See how Corvo handles this workflow
Start with the public page most relevant to what you just read, or get a live quote on your own document before you pay.