--- title: Getting Started | PostGrid description: Introduction to the PostGrid Print & Mail API — covers API keys, test and live modes, available SDKs, and how to structure printable content. --- 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. If you just want to perform one-off sends, you can also do so directly from the API dashboard at ## API Keys 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. ![PostGrid dashboard Settings page showing the Test API Key and Live API Key for a user account](/_astro/01-image.Dgv-H4xF_1ILxfS.webp) You can try out your integration using the **Test API key**. 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. More details can be found [here](https://docs.postgrid.com/#intro), in the official API documentation. With each request, be sure to include the `x-api-key` header with your API key as the value. ## SDKs We currently offer SDKs for two languages: [Python](https://github.com/postgrid/postgrid-python) and [NodeJS](https://github.com/postgrid/postgrid-node-client). Both can be installed from their respective package managers. ## Design 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: | Country | Guideline | | :----------------- | :----------------------------------------------------------------------------------------- | | **Canada** | [Click here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/canada_letter_guideline.pdf) | | **United Kingdom** | [Click here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/letter_guideline_uk.pdf) | | **US & Intl.** | [Click here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/letter_guideline.pdf) | | **Australia** | [Click here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/letter_guideline_au.pdf) | | Country | Page Size | | :----------------- | :------------------ | | **Canada** | 8.5 x 11 inches | | **United Kingdom** | 8.3 x 11.7 inches | | **US & Intl.** | 8.5 x 11 inches | | **Australia** | 8.25 x 11.75 inches | All content underneath the indicated region is covered. If you do not want this, you can also insert a blank page just for the address via the letters API **`addressPlacement`** parameter. For postcards, the guideline varies depending on size and country. Refer to the following table **Canada** | Country | Page Size | | :------- | :------------------------------------------------------------------------------------------------------------------ | | **6x4** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_6x4_ca.pdf) to view the guideline | | **9x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_9x6_ca.pdf) to view the guideline | | **11x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_11x6_ca.pdf) to view the guideline | **United Kingdom & Europe** | Country | Page Size | | :------- | :------------------------------------------------------------------------------------------------------------------ | | **6x4** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/uk_postcard_guideline_6x4.pdf) to view the guideline | | **9x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/uk_postcard_guideline_9x6.pdf) to view the guideline | | **11x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/uk_postcard_guideline_11x6.pdf) to view the guideline | *Note that for the UK postcards, the red zone’s width is half the width of the postcard itself.* **US & International** | Country | Page Size | | :------- | :--------------------------------------------------------------------------------------------------------------- | | **6x4** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_6x4.pdf) to view the guideline | | **9x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_9x6.pdf) to view the guideline | | **11x6** | Click [here](https://pg-prod-bucket-1.s3.amazonaws.com/assets/postcard_guideline_11x6.pdf) to view the 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. ## Letter Size 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`**. | Country | Allowed Options | | :-------------------- | :------------------------------ | | **US** | **`us_letter`**, **`us_legal`** | | **UK** | **`a4`** | | **Rest of the world** | **`us_letter`** | ## Cheque Size 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`**. | Country | Allowed Options | | :-------------------- | :------------------------------ | | **US** | **`us_letter`**, **`us_legal`** | | **Rest of the world** | **`us_letter`** | ## Authorization 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. ## Request Bodies 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. ## Idempotent Requests Our API supports [idempotence](https://en.wikipedia.org/wiki/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. ## Errors All of our error responses contain an **`error`** top-level object. This is what it looks like. | Name | Type | Description | | :------ | :----- | :-------------------------------------------------------------- | | type | string | An computer friendly stable string like **`invalid_pdf_error`** | | message | string | A human-readable description of the error | ## Lists and Pagination 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. ## Search 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`**. ## Expansions 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. 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. ## Metadata Every object in the API can have arbitrary **`metadata`** attached to it. For example, you can tag yourletters with a campaign ID: ``` { // Other letter fields... "metadata": { "campaignID": "ABC" } } ``` You can then get analytics on these letters using the advanced search functionality in the dashboard. The metadata object must not exceed ***10kb of uncompressed storage***. ## Merge Variables 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 | Name | Type | Description | | :------- | :------ | :---------------------------------------------------------------- | | **to** | Contact | The recipient info e.g. **`to.firstName`**, **`to.companyName`** | | **from** | Contact | The sender info e.g. **`from.firstName`**, **`from.companyName`** | ## PDF Previews 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.