Skip to content
Get startedDashboardSupport
Print & Mail

Core Concepts

Cross-cutting concepts for the PostGrid Print & Mail API — test mode, design guidelines, mailing classes, idempotency, errors, search, expansions, metadata, merge variables, tracking, and more.

A simple API to send letters, postcards, and cheques. You can integrate this API to automate your transactional mailings and/or provide offline sending capabilities to your users.

Prefer to work in your own tooling? Download the OpenAPI spec to import the API into Postman, Insomnia, a code generator, or any OpenAPI-compatible app.

Download the OpenAPI spec

If you just want to perform one-off sends, you can also do so directly from the API dashboard at https://dashboard.postgrid.com

Take a look at our guides for information on how to get started.

Every user in your organization will be provided 2 API keys which they can access from their settings: the test key and the live key. Any API calls made with the test key operate in an isolated sandbox. None of the resources you manage in test mode will affect your live environment, and vice versa.

You can try out your integration using the test API keys. There is no difference other than the fact that we do not verify addresses in test mode. Also, more importantly, none of the orders made in test mode will be sent out. Once you’ve tested your integration, you can switch to the live API key and it will just work.

Test orders will also transition from ready to completed at the same time (equivalent) live orders would transition into printing.

There are two primary ways of providing printable content to this API: you can either send predesigned PDFs or provide HTML with personalizable variables. In either case, the address information will automatically be stamped on the final mailing.

For letters, the destination and return addresses are stamped on the first page of your mailing by default. Refer to the following table:

CountryPage SizeGuideline
Canada8.5 x 11 inchesView guideline
United Kingdom8.3 x 11.7 inchesView guideline
US & Intl.8.5 x 11 inchesView guideline
Australia8.3 x 11.7 inchesView guideline

PostGrid will automatically cancel orders if it detects that there is content underneath the address region. If you are not able to accommodate the address region in your design, you can also insert a blank page just for the address via the letters API addressPlacement parameter.

If you have the plastic card inserts feature enabled, your plastic card templates/PDF files must follow the plastic card insert guideline.

For postcards, the guideline varies depending on size and country. Refer to the following table

Canada:

SizeGuideline
6x4View guideline
9x6View guideline
11x6View guideline

United Kingdom & Europe:

SizeGuideline
6x4View guideline
9x6View guideline
11x6View guideline

Note that for the UK postcards, the red zone’s width is half the width of the postcard itself.

US & International:

SizeGuideline
6x4View guideline
9x6View guideline
11x6View guideline

For cheques, the message HTML can cover 7 inches from the top of the first page to the top of the cheque. There is a 0.3in margin applied to this message as it is required for optimal printing.

For self mailers, the guideline varies depending on the size/type of self mailer you’re sending:

US & International:

SizeGuideline
8.5x11_bifoldView guideline
8.5x11_trifoldView guideline

Access our Zapier integration to connect over 1300 apps with PostGrid’s print & mail capabilities without writing any code.

Every order contains a status field with one of the following values

StatusDescription
readyThe order was created successfully and will be printed on sendDate
printingThe order has been given to a printer and will be processed within our SLA
processed_for_deliveryThe order has been handed off to the local postal service
completedThe order has most likely been delivered. This is an approximation.
cancelledThe order has been cancelled and will never be sent out

See the intelligent-mail tracking section below for more detailed tracking information that we provide in the US.

Live orders destined for the US have an imbStatus field added to them once they are processed at a USPS facility. This field has one of the following values

StatusDescription
entered_mail_streamThe order has entered a USPS facility.
out_for_deliveryThe order has been processed at its final USPS facility and will deliver within a day.
returned_to_senderThe order has been returned to the sender.

Additionally, the fields imbDate and imbZIPCode are included to provide more details about the mailing’s journey.

The imbDate represents the date when the mailing was last scanned at a USPS facility, and the imbZIPCode indicates the postal code of that facility. These fields are updated as your order progresses through the USPS processing stages.

By default, all mail is sent as First Class or the fastest non-express postage available in the destination country. You can override this by supplying a specific mailingClass value. For instance, for a lower postage you can supply a mailingClass parameter with value of standard_class to your API calls.

The table below is an exhaustive list of the possible mailingClass values.

Mailing ClassDescription
first_classGeneric first class mail. A suitable carrier will be automatically chosen to send the first class mail.
standard_classGeneric standard class mail. A suitable carrier will be automatically chosen to send the standard class mail
expressGeneric express mail. A suitable carrier will be automatically chosen to send the express mail.
certifiedGeneric certified mail. A suitable carrier will be automatically chosen to send the certified mail. See Certified and Registered Mail for more information.
certified_return_receiptGeneric certified mail with return receipt. A suitable carrier will be automatically chosen to send the certified mail with return receipt. See Certified and Registered Mail for more information.
registeredGeneric registered mail. A suitable carrier will be automatically chosen to send the registered mail. See Certified and Registered Mail for more information.
usps_first_classFirst class mail sent through USPS.
usps_standard_classStandard class mail sent through USPS.
usps_express_3_dayUSPS Priority Mail (2-3 day); Expedited USPS shipping tracking.
usps_first_class_certifiedFirst class certified mail sent through USPS. See Certified and Registered Mail for more information.
usps_first_class_certified_return_receiptFirst class certified mail with return receipt sent through USPS. See Certified and Registered Mail for more information.
ca_post_lettermailLettermail mail sent through Canada Post.
ca_post_personalizedPersonailzed mail sent through Canada Post.
ca_post_registeredGeneric registered mail sent through Canada Post.
ca_post_expedited_with_signatureExpedited mail with signature sent through Canada Post.
ca_post_expeditedExpedited mail sent through Canada Post
ca_post_xpresspost_with_signatureXpresspost mail with signature sent through Canada Post.
ca_post_xpresspostXpresspost mail sent through Canada Post.
royal_mail_first_classFirst class mail sent through Royal Mail.
royal_mail_standard_classStandard class mail sent through Royal Mail.
au_post_regularRegular class mail sent through Australian Post.
ups_express_overnightOvernight express mail sent through UPS; only supported in Canada at the moment
ups_express_2_day2-day express mail sent through UPS; only supported in Canada at the moment
ups_express_3_day3-day express mail sent through UPS; only supported in Canada at the moment
ups_express_3_day_signature_confirmation3-day express mail sent through UPS; only supported in Canada at the moment
ups_express_3_day_adult_signature_confirmation3-day express mail sent through UPS; only supported in Canada at the moment

By default, the letter size will be chosen based on the destination country. You can override this to get a specific letter size by supplying a size parameter with one of the other size options us_letter, us_legal, a4.

CountryAllowed Options
USus_letter
UKa4
Rest of the worldus_letter

By default, the cheque size will be chosen based on the destination country. You can override this to get a specific cheque size by supplying a size parameter with one of the other size options us_letter or us_legal.

CountryAllowed Options
USus_letter
Rest of the worldus_letter

You can cancel orders while they are still in the ready status. For orders scheduled in advance, this typically means you can cancel them until 12AM eastern time on its sendDate. For orders that are scheduled to send ASAP, you should be able to cancel until 12AM eastern time on the following day.

For example, if you create an order without a sendDate (i.e. send ASAP) at 3PM eastern time on 2020-09-14, you can cancel it until 12AM eastern time on 2020-09-15.

All requests here can be authorized via an x-api-key header. If you’re using cURL, you can also supply the key using the shorthand -u YOUR_API_KEY:

You can retrieve your API key from the dashboard inside the Settings page.

All request bodies can be specified in application/json or application/x-www-form-urlencoded. For the endpoints that require uploading a file, you can supply the body as multipart/form-data.

Note that the examples here use the URL encoded format. However, this maps easily into JSON. Wherever you see e.g. to[addressLine1]=Example, that’s equivalent to

"to": { "addressLine1": "Example" }

in JSON.

We have different rate limits depending on the type of request.

For orders (letters, postcards, cheques, self mailers, boxes) and resources (contacts, templates, bank accounts, return envelopes, trackers).

RequestLimit
POST Create1000/minute
GET Individual50/minute
GET List10/minute

If you do exceed our rate limit we will return a 429 status code. We recommend using an exponential backoff with jitter retry strategy along with making use of our idempotent requests feature.

Our API supports idempotence on our order creation endpoints. This allows you to safely retry API calls without creating duplicate orders. This also makes your code more robust in the presence of network issues which disrupt API calls. As such, we highly recommend you make use of this feature.

In order to make your order creation calls idempotent, you must supply an additional Idempotency-Key: header. If your request validates successfully, we will ensure that subsequent requests with an identical idempotency key made up to 24 hours after the initial will return the exact same response without creating any orders. This includes error responses.

You are free to generate your keys however you like, but we suggest using V4 UUIDs.

All of our error responses contain an error top-level object. This is what it looks like.

NameTypeDescription
typestringAn computer friendly stable string like invalid_pdf_error
messagestringA human-readable description of the error

PostGrid uses standard HTTP codes to indicate successful or failed API requests. Successful operations will return 2xx codes. Responses with 4xx codes usually indicate input errors and 5xx codes indicate a server error.

Please refer to the documentation below for more details.

Error ConditionStatus CodeCodeMessage
Your API key could have an incorrect value or be missing from your request headers.401missing_auth_errorMissing or invalid authentication.
401invalid_oauth_token_errorInvalid OAuth token.
Your API key is incorrect. Learn how to access your API keys.401invalid_api_key_errorInvalid API key ${keyValue}
Error ConditionStatus CodeCodeMessage
403limit_reached_errorYou have reached your mailing limit for the month (${limit}). Upgrade to send more.
It is necessary to add a payment method in order to use live mode. Learn more about setting up a payment method.403org_missing_payment_method_errorYou have not attached a payment method so you cannot access the live API.
403org_not_subscribed_errorYou are not subscribed so you cannot do this.
It is necessary to attach a payment method to your PostGrid account to access live mode. If you made an external payment, contact PostGrid support to enable live access to your account.401live_permissions_missing_errorYou do not have permission to complete live requests. Contact your administrator to gain live access.
429rate_limit_exceeded_errorRate limit exceeded.
403self_mailers_not_enabled_errorSelf mailers are not enabled for this organization.
400expired_url_errorThe URL you are trying to access has expired.
422url_generation_errorFailed to generate URL for tracker.
Error ConditionStatus CodeCodeMessage
Missing signature text or image when creating a bank account.400missing_signature_image_errorMissing signature image or signature text.
Invalid signature image type (must be PNG/JPEG).400invalid_signature_image_typeInvalid signature image type ${mimetype} when expecting one of [‘image/jpeg’, ‘image/png’]
400invalid_protocol_errorPlease use the ‘https’ protocol for the url: ${url}
400express_extra_service_unsupported_errorCannot create an order with both extra service and express delivery.
400missing_contact_name_errorMissing first name and company name on contact. At least one must be provided.
You must provide a valid ISO 3611-1 country code when creating contacts.400missing_contact_country_errorMissing country information on contact.
400multiple_countries_in_batch_errorProvided multiple destination countries ${countryCodeA} and ${countryCodeB}. Please make sure all letters are destined for the same country.
400no_valid_contacts_in_batch_errorThere are no valid contacts in this batch; make sure the country of the contacts is set correctly or adjust your address strictness setting.
400validation_errorFailed to satisfy the following constraints: ${errors}
400invalid_pdf_errorUnable to get PDF information. The file or the link you provided might be incorrect.
Please refer to our design guidelines for the expected PDF dimensions for each country.400pdf_incorrect_size_errorFile has incorrect page dimensions ${width}x${height} when expecting ${expectedWidth}x${expectedHeight}.
The provided PDF has pages with different sizes. Please check and resize the PDF according to the design guidelines.400pdf_inconsistent_page_dimensions_errorFile has minimum ${dimension} of ${minDimension} and a maximum of ${maxDimension} when expecting similar values.
400pdf_invalid_page_rotation_errorPage ${ page} in PDF has invalid rotation of ${rotation}
400pdf_incorrect_page_count_errorFile has an incorrect number of pages ${pageCount} when expecting ${expectedPageCount}.
The order status is either complete or cancelled. Therefore, it cannot be progressed.422invalid_progression_errorCannot progress order ${id} from status ’${status}’ because it is terminal.
400could_not_resolve_errorCould not resolve the domain for the URL ”${url}“
The search parameter may be incorrectly formatted. Learn more about search query syntax.400invalid_search_query_errorThe syntax of the search query is incorrect. Make sure it is valid JSON.
400insert_blank_page_perforate_errorCannot insert blank page for address and also perforate the first page. Please disable one or the other.
The selected mailing class is not available for the selected country. See the list of available mailing classes.400mailing_class_not_supported_for_country_errorThe mailing class ${mailingClass} is not available for the country code ${countryCode}.
400${collateral}_size_not_available_errorThe requested ${collateral} size ${requestedSize} is not available for destination country ’${destCountryCode}’. Please choose one of ${availableSizes}
422pdf_workflow_run_not_waiting_for_confirmation_errorAttempted to confirm a workflow run ${runID} whose status is not waiting_for_confirmation.
400pdf_workflow_missing_last_send_jobThe last job in a PDF workflow must be a send job. See the API documentation for the various send jobs available.
400pdf_workflow_multiple_send_jobs_errorPDF workflows cannot contain multiple send jobs. Send jobs must be the last job in a workflow.
400pdf_workflow_invalid_job_sequence_errorYou cannot have a ’${prevJobType}’ job followed by a ’${nextJobType}’ job in a PDF workflow. The following job types are valid inputs to a ’${nextJobType}’ job: ${validInputJobs}.
You cannot retrieve a postal cheque (non-digital) using this endpoint.400cheque_not_digital_only_errorCheque is not digital only.
Error ConditionStatus CodeCodeMessage
The resource (such as order, user, template, etc.) with the specified ID could not be found.404${object}_not_found_errorCould not find ${object} with id ${id}
404contact_not_found_errorContact with ID ${id} was not found.
404no_users_found_errorNo users could be found with your organization
404email_not_found_errorUser with email ${email} not found.
400url_not_found_errorGot status ${status} when attempting to download PDF from the URL ”${url}“
Error ConditionStatus CodeCodeMessage
422duplicate_contact_info_errorThere is already a contact with the exact same information.
The return envelope you attempted to use is out of stock. Learn more about ordering return envelopes.422return_envelope_out_of_stock_errorReturn envelope ${id} is out of stock (0 available). Please order more or wait for existing orders to fill.
It is not possible to create a return envelope as one already exists for the selected contact.422return_envelope_already_exists_errorThere is already a return envelope for destination contact ${contactID}.
Error ConditionStatus CodeCodeMessage
422return_envelope_order_cannot_fill_live_errorCan only force-fill return envelope orders in test mode.
422return_envelope_order_cannot_fill_errorCannot fill return envelope order ${id} because its status is not ‘placed’.
The order you attempted to cancel may have already been cancelled or may have progressed beyond the ready status. Please contact PostGrid Support for more assistance.422return_envelope_order_cancel_failed_errorCannot cancel return envelope order ID ${id}.
Same as above.422cancel_failed_errorCannot cancel order ID ${id}.
A postal code is required for sending mail to the selected country.400postal_code_required_errorCannot mail to ${countryCode} without a postal code
Error ConditionStatus CodeCodeMessage
The contact’s address may have failed to verify and your address strictness status may be set to allow_corrected or allow_verified. You can either update your address strictness setting or set the forceVerifiedStatus flag to true.422address_strictness_errorThe address ’${address}’ does not meet the strictness ’${setting}’ because its status is ’${status}
Same as above.422address_strictness_errorThe address containing ’${line1}’ failed to meet your strictness requirement (${setting}) because its status was ${status}
400invalid_address_errorCannot create plausible address from ’${address}’.
Error ConditionStatus CodeCodeMessage
503service_unavailable_errorOur service is temporarily unavailable, please try again.

All of our listing endpoints are paginated and produce responses according to the List schema. These endpoints receive a skip and limit parameter which can be used to traverse the pages. You can traverse a complete list by incrementing skip by limit for each request until skip >= totalCount, where totalCount is returned in the list response.

Our resource listing endpoints such as GET /contacts and GET /letters provide advanced search capabilities. You can perform this search via a search query parameter, or use the search field on our dashboard.

For example GET /v1/contacts?search="New York" (i.e. search="New York") will produce all the contacts that have the exact string "New York" in their body.

You can also perform structured queries like GET /v1/letters?search={"metadata.campaignID": "ABC"} which searches for

{
"metadata.campaignID": "ABC"
}

In other words, this will produce all the letters whose campaignID matches ABC.

Some of our endpoints return resources with nested IDs. For example, when you retrieve a letter that was created from a template, its body will contain the template ID (See Letter). Rather than making a separate API request for the nested template, you can pass along an query parameter like GET /letters?expand[]=template.

This also works for getting the nested bankAccount inside a cheque. However, it is important to note that you cannot do this for the listing endpoints due to its performance implications.

Every object in the API can have arbitrary metadata attached to it. For example, you can tag your letters with a campaign ID:

{
// Other letter fields...
"metadata": {
"campaignID": "ABC"
}
}

You can later get analytics on these letters using the advanced search functionality in the dashboard.

The metadata object must not exceed 10kb of uncompressed storage.

Whenever you supply HTML to the API via a Template, directly inside a Letter, Postcard, or in the message of a Cheque, you can specify variable fields using curly braces like {{variableName}}. You can then supply a mergeVariables object in your POST requests, and provide values for them.

mergeVariables on a request can contain arbitrarily nested objects. For example

{
"income": {
"beforeTax": 100,
"afterTax": 73
}
}

and these can be referenced by using a . to access nested fields {{income.beforeTax}} and {{income.afterTax}}. Note that variable names (e.g. income, beforeTax, afterTax) cannot contain the characters , # $ .

You can also access the following predefined merge variables in your template

NameTypeDescription
toContactThe recipient info e.g. to.firstName, to.companyName
fromContactThe sender info e.g. from.firstName, from.companyName

We provide PDF previews for all orders (including those created in test mode). These previews should be generated a few seconds after you create an order. They can be accessed through the url property of the returned objects or on the dashboard by clicking View PDF on the top-right of the order details page.

In the case of cheques, the previews will censor the account number by padding the last 4 digits of the account number with zeros.

You can provide an extraService parameter to the Letter and Cheque creation endpoints. This parameter will allow you to send certified/registered mail (including certified mail with return receipts). This is currently only available for US mailings. Note that additional charges will apply for these mailings.

Once a tracking number has been generated, a letter.updated or cheque.updated event will be generated and a webhook will be triggered with the trackingNumber field present. It can be retrieved through a GET request or via the raw data in the dashboard. Using this tracking number, you can view the delivery status of the order on the USPS website or using their API.

Here are the possible values you can provide for extraService

ValueDescription
certifiedSend as certified mail
certified_return_receiptSend as certified mail with a return receipt
registeredSend as registered mail

You can also supply specific values to mailingClass to extra service for your orders.

You can request that the first page of a letter is perforated by adding a parameter perforatedPage: 1 to your letters POST request body. The perforation will be done such that the bottom 3rd of the page (3.6 inches from the bottom) can be torn off the letter.

You can send your letters along with a return envelope by supplying a returnEnvelope ID to your POST /letters or POST /cheques API call. Note that you must first order return envelopes using our Return Envelopes API (see the relevant sections).

On select resources, providing a secret parameter allows hiding information from the dashboard and API. This allows external and private information to be used in the final prints without allowing PostGrid users to view this information. The provided resource ID can be used as a token to allow using these secret resources without giving access to their underlying data.

In the event that one of the recipients you’ve mailed to has moved from the address you supplied, PostGrid may redirect the mail to their new address (depending on your subscription tier).

If mail is redirected, the address changes are applied directly to the affected contacts/orders within our API and dashboard. This also issues a webhook {order_type}.updated event where {order_type} is one of letter, postcard, cheque, or self_mailer depending on which type of order was updated.

You can examine the new address by looking at the addressLine1, addressLine2, etc. fields of the contacts. There is also a new addressChange object that gets added to contacts that have changed as a result of a move. See the following for the schema of this object.

NameTypeDescription
processedOnDate (string)The date and time this address change was ingested into our system.
moveYearMonthstringThe MM/YYYY that this contact moved.
oldAddressobjectAn object containing the addressLine1, city, etc of the address prior to the move update.

You can request express shipping for your orders by setting specific options in mailingClass. See Mailing Class for more details.

PostGrid can provide the exact status of an order as provided by the underlying mail carrier when an appropriate mailingClass is used (e.g. USPS certified mail). You can learn more about this feature here: Carrier Tracking

NameTypeDescription
objectstringAlways list
limitintegerThe limit passed into the request
skipintegerThe skip passed into the request
totalCountintegerTotal number of documents in this list, including skipped documents
dataArrayThe requested documents