Shipments
Shipments are the core resource in the Corvo API. A shipment represents a PDF document being printed, packaged, and delivered to a recipient. You always create shipments as drafts to compare rates, then explicitly purchase with the /buy endpoint.
Authentication and billing
All shipment endpoints require a Bearer API key. Creating, buying, and cancelling shipments are rate limited to 30 requests per minute per organization. Listing shipments is limited to 60 requests per minute. Buying a shipment charges the organization card already on file in the dashboard.
Shipment object
Core fields
| Name | Type | Required | Description |
|---|---|---|---|
| id | string (UUID) | Yes | Shipment ID. |
| status | string | Yes | Current shipment status. |
| shipment_name | string | null | Yes | Optional human-readable label you supplied during creation. |
| page_count | integer | Yes | Validated PDF page count. |
| print_options | object | Yes | Current print settings (`color`, `duplex`). |
| shipping_options | object | Yes | Current shipping settings (`delivery_confirmation`, `certified_mail`, `return_receipt`). |
| to_address | object | Yes | Recipient address after verification or correction. Includes `verified` and `residential`. |
| from_address | object | Yes | Return address used for the shipment. May remain `verified: false` if soft verification could not confirm it. |
| tags | array | Yes | Array of `{ id, name }` tag objects. |
| created_at | datetime | Yes | Shipment creation timestamp. |
Delivery and fulfillment fields
| Name | Type | Required | Description |
|---|---|---|---|
| carrier | string | null | Yes | Carrier selected for the purchased shipment, or `null` while still a draft. |
| service | string | null | Yes | Service level selected for the purchased shipment, or `null` while still a draft. |
| tracking_number | string | null | Yes | Tracking number once postage has been purchased. |
| tracking_url | string | null | Yes | Carrier tracking URL when available. |
| selected_quote_id | string | null | Yes | Chosen draft quote ID after purchase, if Corvo can map it back to the stored quote. |
| shipped_at | datetime | null | Yes | Timestamp set when Corvo hands the package to the carrier. |
| delivered_at | datetime | null | Yes | Carrier-confirmed delivery time when available. |
| signer_name | string | null | Yes | Signer name for certified-mail delivery events when available. |
| usps_accepted_at | datetime | null | Yes | USPS acceptance timestamp for certified-mail workflows when available. |
| scan_form_id | string | null | Yes | Internal SCAN form reference when applicable to USPS workflows. |
Pricing fields
| Name | Type | Required | Description |
|---|---|---|---|
| postage_cost_cents | integer | Yes | Raw carrier postage cost stored on the purchased shipment. |
| postage_markup_cents | integer | Yes | Markup applied on top of raw postage for purchased shipments. |
| envelope_fee_cents | integer | Yes | Per-shipment handling fee. |
| page_fee_cents | integer | Yes | Black-and-white page fee component. |
| page_fee_color_cents | integer | Yes | Color surcharge component. |
| tax_amount_cents | integer | Yes | Tax charged on the shipment, if any. |
| total_charged_cents | integer | Yes | Total charged amount in cents. |
Optional fields
| Name | Type | Required | Description |
|---|---|---|---|
| document_preview_url | string | null | Yes | Short-lived preview URL for the uploaded PDF, when Corvo can generate one. |
| document_filename | string | null | Yes | Stored filename for the PDF. |
| events | array | undefined | No | Ordered shipment event timeline. Included on shipment detail responses. |
| rates | array | undefined | No | Draft quote array. Included on shipment creation and on detail responses while the shipment is still `draft` or `payment_failed`. |
| quotes_expire_at | datetime | undefined | No | Shared expiry timestamp for the returned draft quotes. |
| mailing_records | object | undefined | No | Mailing-record state for certified-mail shipments, including acceptance, delivery, return-receipt, and retention details. |
| shipped_data_expires_at | datetime | null | No | Canonical shipped-data purge timestamp. Snapshot when the shipment first becomes shipped and used for warnings and purge scheduling. |
| artifacts | array | undefined | No | Downloadable evidence artifacts for shipment detail responses, including Corvo-generated summary and bundle entries plus retained carrier-backed files. |
Rate quote object
| Name | Type | Required | Description |
|---|---|---|---|
| quote_id | string (UUID) | Yes | Quote ID to pass to `/buy`. |
| carrier | string | Yes | Raw EasyPost carrier value. |
| service | string | Yes | Raw EasyPost service value. |
| postage_cents | integer | Yes | Draft quote postage including Corvo markup. |
| handling_fee_cents | integer | Yes | Handling fee component. |
| printing_fee_cents | integer | Yes | Printing fee component. |
| color_surcharge_cents | integer | Yes | Color surcharge component. |
| total_cents | integer | Yes | Total quoted charge in cents. |
| delivery_days | integer | null | Yes | Carrier delivery-days estimate. |
| delivery_date | datetime | null | Yes | Carrier delivery-date estimate. |
| delivery_date_guaranteed | boolean | Yes | Whether the carrier marked the delivery date as guaranteed. |
Shipment event object
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Event ID. |
| status | string | Yes | New shipment status for the event. |
| from_status | string | null | Yes | Previous status when available. |
| message | string | null | Yes | Human-readable event message. |
| actor | string | null | Yes | Actor such as `user:<id>` or `webhook:printnode`. |
| metadata | object | null | Yes | Event metadata payload when present. |
| created_at | datetime | Yes | Event timestamp. |
Mailing-record object
| Name | Type | Required | Description |
|---|---|---|---|
| acceptance | object | Yes | Acceptance workflow state, including whether postage was purchased, whether a SCAN form/tender event exists, and whether USPS acceptance has been recorded. |
| delivery | object | Yes | Latest carrier delivery state, including delivered, attempted, signer, and return-to-sender timestamps when available. |
| return_receipt | object | Yes | Return-receipt request state and any linked retained return-receipt artifact. |
| retention | object | Yes | Snapshot-driven shipped retention details, including the canonical purge date used for original PDFs and retained evidence. |
Artifact object
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Artifact identifier. |
| kind | string | Yes | Artifact type such as `mailing_record_summary_pdf` or `carrier_scan_form_pdf`. |
| source | string | Yes | Artifact source, for example `corvo` or `easypost`. |
| provenance | string | Yes | One of `carrier_native`, `carrier_event`, or `corvo_generated`. |
| status | string | Yes | Artifact state such as `available`, `failed`, or `expired`. |
| filename | string | null | Yes | Suggested download filename. |
| content_type | string | null | Yes | Artifact content type when known. |
| available_at | datetime | null | Yes | When the artifact became available. |
| expires_at | datetime | null | Yes | When the artifact is scheduled to expire, if known. |
| download_url | string | null | Yes | Authenticated Corvo download path for the artifact. |
Create a draft shipment
POST
/api/v1/shipmentsCreate a draft shipment and return live quotes. Purchase is always a separate `/buy` call.
Request behavior
At least one of
document_key or document is required. If both are sent, the current implementation uses document_key and ignores the inline base64 payload.Top-level request body
| Name | Type | Required | Description |
|---|---|---|---|
| document_key | string | No | Previously uploaded document key. |
| document | string | No | Base64-encoded PDF. Useful for simple server-to-server flows. |
| shipment_name | string | No | Optional human-readable label for your own dashboard and reporting. |
| to_address | object | Yes | Recipient address object. |
| from_address | object | No | Return address object. If omitted, Corvo uses the organization default return address from the dashboard. |
| print_options | object | Yes | Print settings object. |
| shipping_options | object | No | Optional quote filters and USPS options. |
| tags | string[] | No | Optional array of tag names. Maximum 50. |
Address object
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | No | Full name. At least one of `name` or `company` is required. |
| company | string | No | Company name. At least one of `name` or `company` is required. |
| street1 | string | Yes | Street address line 1. |
| street2 | string | No | Street address line 2. |
| city | string | Yes | City. |
| state | string | Yes | State or province. |
| zip | string | Yes | Postal code. |
| country | string | No | Two-letter country code. Defaults to "US". |
| phone | string | No | Phone number. |
| string | No | Email address. |
Print options
| Name | Type | Required | Description |
|---|---|---|---|
| color | boolean | Yes | Print in color when `true`. |
| duplex | boolean | Yes | Print double-sided when `true`. |
Shipping options
| Name | Type | Required | Description |
|---|---|---|---|
| carrier | string | No | Optional carrier filter. Use the raw EasyPost carrier value, for example `USPS`, `FedEx`, or `UPS`. |
| service | string | No | Optional service filter. Requires `carrier` and must use the raw EasyPost service value. |
| delivery_confirmation | string | No | Optional EasyPost delivery-confirmation value such as `SIGNATURE`, `ADULT_SIGNATURE`, or `SIGNATURE_RESTRICTED`. |
| certified_mail | boolean | No | Set `true` to request USPS Certified Mail. |
| return_receipt | boolean | No | Set `true` only when `certified_mail` is also `true`. |
Validation constraints
`return_receipt` requires `certified_mail=true`. Supplying `service` without `carrier` returns
VALIDATION_ERROR. Shipment creation also requires the key owner's email address to be verified.curl -X POST https://corvo.to/api/v1/shipments \
-H "Authorization: Bearer $CORVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"document_key": "documents/org-id/notice.pdf",
"shipment_name": "Eviction Notice",
"to_address": {
"name": "Jordan Reed",
"street1": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
},
"print_options": {
"color": false,
"duplex": true
},
"shipping_options": {
"certified_mail": true,
"return_receipt": true
}
}'Response201Draft shipment
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "draft",
"shipment_name": "Eviction Notice",
"page_count": 4,
"print_options": {
"color": false,
"duplex": true
},
"shipping_options": {
"delivery_confirmation": null,
"certified_mail": true,
"return_receipt": true
},
"to_address": {
"name": "Jordan Reed",
"company": null,
"street1": "123 Main St",
"street2": null,
"city": "Austin",
"state": "TX",
"zip": "78701",
"country": "US",
"phone": null,
"email": null,
"verified": true,
"residential": true
},
"from_address": {
"name": "Acme Property Management",
"company": null,
"street1": "500 Congress Ave",
"street2": null,
"city": "Austin",
"state": "TX",
"zip": "78701",
"country": "US",
"phone": null,
"email": null,
"verified": true,
"residential": false
},
"tags": [
{
"id": "tag_01",
"name": "evictions"
}
],
"created_at": "2026-03-09T15:00:00.000Z",
"rates": [
{
"quote_id": "quote_01",
"carrier": "USPS",
"service": "Priority",
"postage_cents": 855,
"handling_fee_cents": 300,
"printing_fee_cents": 100,
"color_surcharge_cents": 0,
"total_cents": 1255,
"delivery_days": 2,
"delivery_date": "2026-03-11T00:00:00.000Z",
"delivery_date_guaranteed": false
}
],
"quotes_expire_at": "2026-03-09T15:30:00.000Z"
}
}Response404Unknown document key
{
"error": {
"message": "Document not found or does not belong to this organization",
"code": "DOCUMENT_NOT_FOUND"
}
}List shipments
GET
/api/v1/shipmentsList shipments for the authenticated organization.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | Optional shipment status filter. |
| tag | string | No | Optional tag-name filter. |
| limit | integer | No | Results per page. Defaults to 20 and maxes at 100. |
| cursor | string (UUID) | No | Pagination cursor returned as `next_cursor` from the previous page. |
| date_from | date | datetime | No | Start boundary. Accepts `YYYY-MM-DD` or an ISO 8601 datetime with offset. |
| date_to | date | datetime | No | End boundary. Accepts `YYYY-MM-DD` or an ISO 8601 datetime with offset. Date-only values are treated as end-of-day UTC. |
Response shape
List responses return a subset of the shipment object in a
data array plus has_more and next_cursor. Draft-only fields like rates and the event timeline are not included in list results.curl "https://corvo.to/api/v1/shipments?status=shipped&tag=evictions&limit=10" \
-H "Authorization: Bearer $CORVO_API_KEY"Response200Shipment page
{
"data": [
{
"id": "ship_01",
"status": "shipped",
"shipment_name": "Eviction Notice",
"page_count": 4,
"carrier": "USPS",
"service": "Priority",
"tracking_number": "9405511899223033005084",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9405511899223033005084",
"total_charged_cents": 1255,
"created_at": "2026-03-09T15:00:00.000Z",
"shipped_at": "2026-03-10T13:22:00.000Z"
}
],
"has_more": true,
"next_cursor": "ship_01"
}Response400Invalid filter
{
"error": {
"message": "Invalid option: expected one of ...",
"code": "VALIDATION_ERROR"
}
}Retrieve a shipment
GET
/api/v1/shipments/{id}Fetch the current state of a single shipment.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string (UUID) | Yes | Shipment ID. |
API-key polling limit
When you authenticate with an API key, Corvo allows one shipment-detail request per shipment every five minutes and may return a cached response inside that window. Session-based dashboard traffic uses a separate higher-throughput limit.
What detail responses include
Detail responses include the shipment event timeline. They also include draft quotes again while the shipment is still
draft or payment_failed.curl https://corvo.to/api/v1/shipments/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "Authorization: Bearer $CORVO_API_KEY"Response200Shipment detail
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "queued",
"carrier": "USPS",
"service": "Priority",
"tracking_number": "9405511899223033005084",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9405511899223033005084",
"total_charged_cents": 1255,
"created_at": "2026-03-09T15:00:00.000Z",
"shipped_at": null,
"events": [
{
"id": "evt_01",
"status": "payment_pending",
"from_status": "draft",
"message": "Payment initiated for draft shipment",
"actor": "user:4c1b8b16-2e4f-4de0-9ad5-e0ec0f16dbe8",
"metadata": null,
"created_at": "2026-03-09T15:00:04.000Z"
}
]
}
}Response404Shipment not found
{
"error": {
"message": "Shipment not found",
"code": "SHIPMENT_NOT_FOUND"
}
}Buy a draft shipment
POST
/api/v1/shipments/{id}/buyCharge the organization card on file and buy the selected draft quote.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string (UUID) | Yes | Shipment ID. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| quote_id | string (UUID) | Yes | Draft quote ID returned by shipment creation. |
Billing requirements
Buying a shipment fails if the organization has no Stripe customer or no default payment method on file. Configure billing in the dashboard before using the public API for purchases.
curl -X POST https://corvo.to/api/v1/shipments/f47ac10b-58cc-4372-a567-0e02b2c3d479/buy \
-H "Authorization: Bearer $CORVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"quote_id":"quote_01"}'Response200Shipment purchased
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "queued",
"carrier": "USPS",
"service": "Priority",
"total_charged_cents": 1255,
"tracking_number": "9405511899223033005084",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9405511899223033005084"
}
}Response400No payment method on file
{
"error": {
"message": "No payment method on file. Please add a card before creating shipments.",
"code": "NO_PAYMENT_METHOD"
}
}Cancel a shipment
POST
/api/v1/shipments/{id}/cancelCancel a shipment before terminal fulfillment.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string (UUID) | Yes | Shipment ID. |
Allowed statuses
Customer-facing cancellation is allowed only while a shipment is in
draft, queued, or printed.curl -X POST https://corvo.to/api/v1/shipments/f47ac10b-58cc-4372-a567-0e02b2c3d479/cancel \
-H "Authorization: Bearer $CORVO_API_KEY"Response200Shipment cancelled
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "cancelled"
}
}Response409Cannot cancel from current status
{
"error": {
"message": "Invalid status transition from \"shipped\" to \"cancelled\"",
"code": "INVALID_STATUS_TRANSITION"
}
}