postgrid-node-client
postgrid-node-client
is a Node/JS and TypeScript Client for
PostGrid that allows you to use normal Node
syntax to send PDFs, and other documents, through Postal Delivery to
recipients. The second service PostGrid offers
is the Address Verification and Autocomplete. That, too, is covered in
this client, but PostGrid requires two API Keys -
one for each service, so it will be important to keep them straight in
the set-up of the Client, below. PostGrid has
a set of REST endpoints for
the Print-Mail service, and another set of REST
endpoints for the Address
Verification service. This Node client just
affords some nice convenience features for the Node developer.
Install
# with npm
$ npm install postgrid-node-client
Usage
This README isn't going to cover all the specifics of what PostGrid is, and how to use it - it's targeted as a companion to the PostGrid developer Print-Mail docs, and the Address Verification docs that explain each of the endpoints and how the general PostGrid workflow works.
However, we'll put in plenty of examples so that it's clear how to use this library to interact with both PostGrid services.
Getting your API Keys
As documented on the PostGrid sites - one for the Print-Mail, and one for the
Address Verification, the first step is getting an API Key for each service.
This is available on the Print-Mail Dashboard
page, and on the Address
Verification Dashboard
page, once you login to each
of the PostGrid services. For the rest of this document, the API Keys will
be seen as: [Your Mail API Key]
and the Print-Mail service, and
[Your Addr API Key]
and the Address Verification service, and will
need to be replaced with the API Keys you obtain from the site.
If you only subscribe to one service - just get that key. The Client is smart enough to return an error on the calls if you do not have the appropriate API Key for that call.
Creating the Client
All PostGrid functions are available from the client, and the basic construction of the client is:
import { PostGrid } from 'postgrid-node-client'
const client = new PostGrid({
mail: '[Your Mail API Key]',
addr: '[Your Addr API Key]',
})
and it's not necessary that you supply both API Keys if you only have a subscription to one of the services. Just fill in the one you have.
There is a legacy mode where the Print-Mail functions are available by just supplying the API Key for that service. That constructor looks like:
import { PostGrid } from 'postgrid-node-client'
const client = new PostGrid('[Your Mail API Key]')
If you'd like to provide the webhook URL in the constructor, you can do that with:
const client = new PostGrid({
mail: '[Your Mail API Key]',
addr: '[Your Addr API Key]',
},
{
webhookUrl: 'https://my.service.com/postgrid/callback',
webhookSecret: 'abc123456the-tall-brown-bear',
webhookEvents: ['letter.created', 'letter.updated'],
}
)
where the options can include:
-
webhookUrl
- the URL for all PostGrid updates to be sent -
webhookSecret
- the JWT encryption secret for the payload on the webhook so that it's safe in transmission back to the service. -
webhookEvents
- the array of strings that are the events that this webhook is expected to receive from PostGrid.
Contact Calls
In general, the Contacts are the contact information for a Sender or Recipient in the PostGrid system. These can be created, updated, and deleted, as individual entities, or they can be created as a part of a more complex operation - such as Create a Letter.
Create Contact
const contact = await client.contact.create({
addressLine1: '2929 Eagledale Dr',
provinceOrState: 'IN',
postalOrZip: '46224',
countryCode: 'US',
firstName: 'Jim',
lastName: 'Harrison',
email: 'jim@jimmys.com',
phoneNumber: '317-555-1212',
companyName: 'Jimmys Bar',
jobTitle: 'Barkeep',
})
This will create the contact with the provided address and contact information, and in the event that the details are the same as an existing Contact, this will not create a new Contact, but simply return the existing one with the same data. The response will be something like:
{
"success": true,
"contact": {
"id": "contact_igdxsBys7TPJYf47PevBJj",
"object": "contact",
"live": false,
"addressLine1": "2929 EAGLEDALE DR",
"addressLine2": null,
"addressStatus": "verified",
"city": null,
"companyName": "Jimmys Bar",
"country": "UNITED STATES",
"countryCode": "US",
"email": "jim@jimmys.com",
"firstName": "Jim",
"jobTitle": "Barkeep",
"lastName": "Harrison",
"phoneNumber": "317-555-1212",
"postalOrZip": "46224",
"provinceOrState": "IN",
"createdAt": "2021-07-15T18:36:45.348Z",
"updatedAt": "2021-07-15T18:36:45.348Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
So looking at the success
value of the response will quickly let you know the outcome of the call.
Get a Contact
const doc = await client.contact.get(id)
where id
is the Contact ID, like contact_igdxsBys7TPJYf47PevBJj
, in the
above example, and the response will be something like the response to the
client.contact.create()
function.
List Contacts
const doc = await client.contacts.list()
This will list all the Contacts assoiated with this API Key, and will do so
in the PostGrid List paging scheme of limit
and skip
. These parameters
are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"contacts": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 12,
"data": [
{
"id": "contact_2rWLmfNFPKQLtZEy72qT8e",
"object": "contact",
"live": false,
"addressLine1": "2929 EAGLEDALE DR",
"addressLine2": null,
"addressStatus": "verified",
"city": null,
"companyName": "Jimmys Bar",
"country": "UNITED STATES",
"countryCode": "US",
"email": "jim@jimmys.com",
"firstName": "Jim",
"jobTitle": "Barkeep",
"lastName": "Harrison",
"phoneNumber": "317-555-1212",
"postalOrZip": "46224",
"provinceOrState": "IN",
"createdAt": "2021-07-15T18:54:44.521Z",
"updatedAt": "2021-07-15T18:54:44.521Z"
},
...
]
}
}
Delete a Contact
const doc = await client.contact.delete(id)
where id
is the Contact ID, like contact_igdxsBys7TPJYf47PevBJj
, in the
above example, and the response will be something like:
{
"success": true,
"contact": {
"id": "contact_2gA88Z5Mb3jtB1nnpQCCAn",
"object": "contact",
"deleted": true
}
}
Letter Calls
The PostGrid Letter is a basic Page Document that can be sourced from an HTML template, with replacable parameters, or a PDF, and can be sent from a Sender to a Recipient through the Postal System.
Create Letter
The basic Create Letter call looks something like this:
const letter = await client.letter.create({
description: 'Cool new letter',
pdf: 'https://www.icnaam.org/documents/8x11singlesample.pdf',
to: {
firstName: 'Steve',
lastName: 'Smith',
companyName: 'Acme Rentals',
addressLine1: '5454 West 34th Street',
city: 'Indianapolis',
provinceOrState: 'IN',
postalOrZip: '46224',
countryCode: 'US',
},
from: {
firstName: 'John',
lastName: 'Quincy',
companyName: 'US Steel',
addressLine1: '123 Main Street',
city: 'Atlanta',
provinceOrState: 'GA',
postalOrZip: '12345',
countryCode: 'US',
},
})
This will create the letter with the provided addresses, and in it will then start it's journey to the recipient. The response will be something like:
{
"success": true,
"letter": {
"id": "letter_hBy6M5DMKEqp7z1paW1TDM",
"object": "letter",
"live": false,
"addressPlacement": "insert_blank_page",
"color": false,
"description": "Cool new letter",
"doubleSided": false,
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"sendDate": "2021-07-15T19:51:50.356Z",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"uploadedPdf": "https://pg-prod-bucket-1.s3.amazonaws.com/test/...",
"createdAt": "2021-07-15T19:51:50.360Z",
"updatedAt": "2021-07-15T19:51:50.360Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
It's important to remember that if the same Contact information is supplied as an existing Contact, PostGrid will not create a new Contact - simply reuse the one it already has.
But there are other ways to create a letter. You can use the Contact IDs, like:
const letter = await client.letter.create({
description: 'Cool new letter',
pdf: 'https://www.icnaam.org/documents/8x11singlesample.pdf',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
})
so that if you know the created Contact data, you can just pass in the IDs. Of course, you can mix-and-match as well.
You can also use a standard Node Buffer
to load up the Letter source:
import fs from 'fs'
const doc = fs.readFileSync('/my/local/file.pdf')
const letter = await client.letter.create({
description: 'Cool new letter',
pdf: doc,
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
})
all of these are covered in the different forms of the PostGrid Create Letter endpoints, but the Client detects the inputs and acts accordingly. You just have to provide the data.
As a final note, you can also pass in the optional Idempotency Key to the
create()
function, and this will have the added benefit that PostGrid will
not create a duplicate Letter - within 24 hrs, of the initial create()
call
with the same idempotencyKey
. The key is provided in the call as an optional
second parameter:
const letter = await client.letter.create({
description: 'Cool new letter',
pdf: 'https://www.icnaam.org/documents/8x11singlesample.pdf',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
}, {
idempotencyKey: '9d972254-34eb-492e-90c2-739087a8487d'
})
where this example is just using a UUID.
Get a Letter
const doc = await client.letter.get(id)
where id
is the Letter ID, like letter_hBy6M5DMKEqp7z1paW1TDM
, in the
above example, and the response will be something like the response to the
client.letter.create()
function.
List Letters
const doc = await client.letter.list()
This will list all the Letters assoiated with this API Key, and will do so
in the PostGrid List paging scheme of limit
and skip
. These parameters
are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"letters": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 27,
"data": [
{
"id": "letter_3j3st1ZzZmFPv9bn1BnMeE",
"object": "letter",
"live": false,
"addressPlacement": "insert_blank_page",
"color": false,
"description": "Cool new letter",
"doubleSided": false,
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"sendDate": "2021-07-15T20:02:55.417Z",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"uploadedPdf": "https://pg-prod-bucket-1.s3.amazonaws.com/test/...",
"createdAt": "2021-07-15T20:02:55.421Z",
"updatedAt": "2021-07-15T20:02:55.421Z"
},
...
]
}
}
Progress a Test Letter
This function will move a Test Letter through the server-side processing steps, one at a time to allow the caller to verify the webhook calls. This is only available for Test Letters.
const move = await client.letter.progress(id)
where id
is the Letter ID, like letter_hBy6M5DMKEqp7z1paW1TDM
, in the
above example, and the response will be similar to the response from
client.letter.get(id)
.
Delete a Letter
This function will delete - or Cancel a Letter that's not yet been sent.
const doc = await client.letter.delete(id)
where id
is the Letter ID, like letter_hBy6M5DMKEqp7z1paW1TDM
, in the
above example, and the response will be something like:
{
"success": true,
"letter": {
"id": "letter_hBy6M5DMKEqp7z1paW1TDM",
"object": "letter",
"deleted": true
}
}
Postcard Calls
The PostGrid Postcard is a basic postcard that can be sourced from an HTML template, with replacable parameters, or a PDF, and can be sent from a Sender to a Recipient through the Postal System. The available sizes are:
6x4
9x6
11x6
which is specified in the size
parameter of the postcard.create()
function call.
Create Postcard
The basic Create Postcard call looks something like this:
const postcard = await client.postcard.create({
description: 'Cool new postcard',
size: '6x4',
frontHTML: 'Hello, {{to.firstName}}',
backHTML: 'Hello again, {{to.firstName}}',
to: {
firstName: 'Steve',
lastName: 'Smith',
companyName: 'Acme Rentals',
addressLine1: '5454 West 34th Street',
city: 'Indianapolis',
provinceOrState: 'IN',
postalOrZip: '46224',
countryCode: 'US',
},
from: {
firstName: 'John',
lastName: 'Quincy',
companyName: 'US Steel',
addressLine1: '123 Main Street',
city: 'Atlanta',
provinceOrState: 'GA',
postalOrZip: '12345',
countryCode: 'US',
},
})
This will create the postcard with the provided addresses, and in it will then start it's journey to the recipient. The response will be something like:
{
"success": true,
"postcard": {
"id": "postcard_48Fm3w14DGjRKKpsD2GrXJ",
"object": "postcard",
"live": false,
"backHtml": "Hello again, {{to.firstName}}",
"description": "Cool new postcard",
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"frontHtml": "Hello, {{to.firstName}}",
"sendDate": "2021-07-16T14:09:38.286Z",
"size": "6x4",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"createdAt": "2021-07-16T14:09:38.290Z",
"updatedAt": "2021-07-16T14:09:38.290Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
It's important to remember that if the same Contact information is supplied as an existing Contact, PostGrid will not create a new Contact - simply reuse the one it already has.
But there are other ways to create a postcard. You can use the Contact IDs, like:
const postcard = await client.postcard.create({
description: 'Cool new postcard',
pdf: 'https://my.artwork.com/postcards/6x4sample.pdf',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
})
so that if you know the created Contact data, you can just pass in the IDs. Of course, you can mix-and-match as well.
You can also use a standard Node Buffer
to load up the Letter source:
import fs from 'fs'
const doc = fs.readFileSync('/my/local/file.pdf')
const postcard = await client.postcard.create({
description: 'Cool new postcard',
pdf: doc,
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
})
all of these are covered in the different forms of the PostGrid Create Postcard endpoints, but the Client detects the inputs and acts accordingly. You just have to provide the data.
As a final note, you can also pass in the optional Idempotency Key to the
create()
function, and this will have the added benefit that PostGrid will
not create a duplicate Postcard - within 24 hrs, of the initial create()
call
with the same idempotencyKey
. The key is provided in the call as an optional
second parameter:
const postcard = await client.postcard.create({
description: 'Cool new postcard',
pdf: 'https://my.artwork.com/postcards/6x4sample.pdf',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
}, {
idempotencyKey: '9d972254-34eb-492e-90c2-739087a8487d'
})
where this example is just using a UUID.
Get a Postcard
const doc = await client.postcard.get(id)
where id
is the Postcard ID, like postcard_48Fm3w14DGjRKKpsD2GrXJ
, in the
above example, and the response will be something like the response to the
client.postcard.create()
function.
List Postcards
const doc = await client.postcard.list()
This will list all the Postcards assoiated with this API Key, and will do so
in the PostGrid List paging scheme of limit
and skip
. These parameters
are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"postcards": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 3,
"data": [
{
"id": "postcard_agV7LbeDfRbdNUdnfePAyD",
"object": "postcard",
"live": false,
"backHtml": "Hello again, {{to.firstName}}",
"description": "Cool new postcard",
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"frontHtml": "Hello, {{to.firstName}}",
"sendDate": "2021-07-16T14:14:37.023Z",
"size": "6x4",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"createdAt": "2021-07-16T14:14:37.027Z",
"updatedAt": "2021-07-16T14:14:37.027Z"
},
{
"id": "postcard_48Fm3w14DGjRKKpsD2GrXJ",
"object": "postcard",
"live": false,
"backHtml": "Hello again, {{to.firstName}}",
"description": "Cool new postcard",
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"frontHtml": "Hello, {{to.firstName}}",
"pageCount": 2,
"sendDate": "2021-07-16T14:09:38.286Z",
"size": "6x4",
"status": "cancelled",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"url": "https://pg-prod-bucket-1.s3.amazonaws.com/test/...",
"createdAt": "2021-07-16T14:09:38.290Z",
"updatedAt": "2021-07-16T14:09:42.691Z"
},
...
]
}
}
Progress a Test Postcard
This function will move a Test Postcard through the server-side processing steps, one at a time to allow the caller to verify the webhook calls. This is only available for Test Postcards.
const move = await client.postcard.progress(id)
where id
is the Postcard ID, like postcard_agV7LbeDfRbdNUdnfePAyD
, in the
above example, and the response will be similar to the response from
client.postcard.get(id)
.
Delete a Postcard
This function will delete - or Cancel a Postcard that's not yet been sent.
const doc = await client.postcard.delete(id)
where id
is the Postcard ID, like postcard_agV7LbeDfRbdNUdnfePAyD
, in the
above example, and the response will be something like:
{
"success": true,
"postcard": {
"id": "postcard_agV7LbeDfRbdNUdnfePAyD",
"object": "postcard",
"deleted": true
}
}
Bank Account Calls
In general, the Bank Accounts are the account information for creating a check/cheque in the PostGrid system. These accounts can be created, updated, and deleted, as individual entities.
Create Bank Account
const account = await client.bankAccount.create({
description: 'This is where to put your marshmallows',
bankName: 'Bank of Marshmallows',
bankPrimaryLine: '3288 Tara Lane',
bankSecondaryLine: 'Indianapolis, IN',
bankCountryCode: 'US',
routingNumber: '123456789',
accountNumber: '100010001001',
signatureText: 'Stay Puff'
})
This will create the account with the provided address and account information. The response will be something like:
{
"success": true,
"account": {
"id": "bank_gMpKxPyiGzt1ZwACTmLHHn",
"object": "bank_account",
"live": false,
"accountNumberLast4": "1001",
"bankCountryCode": "US",
"bankName": "Bank of Marshmallows",
"bankPrimaryLine": "3288 Tara Lane",
"bankSecondaryLine": "Indianapolis, IN",
"description": "This is where to put your marshmallows",
"routingNumber": "123456789",
"signatureText": "Stay Puff",
"createdAt": "2021-07-18T16:19:35.626Z",
"updatedAt": "2021-07-18T16:19:35.626Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
So looking at the success
value of the response will quickly let you know the outcome of the call.
Get a Bank Account
const account = await client.bankAccount.get(id)
where id
is the Bank Account ID, like bank_gMpKxPyiGzt1ZwACTmLHHn
, in the
above example, and the response will be something like the response to the
client.bankAccount.create()
function.
List Bank Accounts
const accts = await client.bankAccount.list()
This will list all the Bank Accounts assoiated with this API Key, and will
do so in the PostGrid List paging scheme of limit
and skip
. These
parameters are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"accounts": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 1,
"data": [
{
"id": "bank_a2M4zstWGeYeJ8gbtVKKr5",
"object": "bank_account",
"live": false,
"accountNumberLast4": "1001",
"bankCountryCode": "US",
"bankName": "Bank of Marshmallows",
"bankPrimaryLine": "3288 Tara Lane",
"bankSecondaryLine": "Indianapolis, IN",
"description": "This is where to put your marshmallows",
"routingNumber": "123456789",
"signatureText": "Stay Puff",
"createdAt": "2021-07-18T16:22:44.579Z",
"updatedAt": "2021-07-18T16:22:44.579Z"
}
]
}
}
Delete a Bank Account
const drop = await client.bankAccount.delete(id)
where id
is the Bank Account ID, like bank_a2M4zstWGeYeJ8gbtVKKr5
, in the
above example, and the response will be something like:
{
"success": true,
"account": {
"id": "bank_a2M4zstWGeYeJ8gbtVKKr5",
"object": "bank_account",
"deleted": true
}
}
Cheque/Check Calls
The PostGrid Cheque (Check) is a check written against a Bank Account that
can be sent to the to
recipient with an optional letter sourced from an
in-line HTML blob, a Template, or a PDF, and will be sent from
a Sender to a Recipient through the Postal System.
Create Check
The basic Create Check call looks something like this:
const check = await client.check.create({
description: 'Cool new check',
letterHTML: 'Hello {{to.firstName}}',
to: {
firstName: 'Steve',
lastName: 'Smith',
companyName: 'Acme Rentals',
addressLine1: '5454 West 34th Street',
city: 'Indianapolis',
provinceOrState: 'IN',
postalOrZip: '46224',
countryCode: 'US',
},
from: {
firstName: 'John',
lastName: 'Quincy',
companyName: 'US Steel',
addressLine1: '123 Main Street',
city: 'Atlanta',
provinceOrState: 'GA',
postalOrZip: '12345',
countryCode: 'US',
},
bankAccount: 'bank_gMpKxPyiGzt1ZwACTmLHHn',
amount: 10000,
memo: 'Invoice 1233',
number: 9667,
})
This will create the check with the provided addresses, against the Bank
Account referenced by bank_gMpKxPyiGzt1ZwACTmLHHn
, and will include a
letter in the same envelope, with the contents of the letterHTML
. The
response will be something like:
{
"success": true,
"check": {
"id": "cheque_7GrdUQPmbkAXJg8vLkJK9B",
"object": "cheque",
"live": false,
"amount": 10000,
"bankAccount": "bank_gMpKxPyiGzt1ZwACTmLHHn",
"currencyCode": "USD",
"description": "Cool new check",
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"letterHtml": "Hello {{to.firstName}}",
"memo": "Invoice 1233",
"number": 9667,
"sendDate": "2021-07-19T09:57:28.214Z",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"createdAt": "2021-07-19T09:57:28.220Z",
"updatedAt": "2021-07-19T09:57:28.220Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
It's important to remember that if the same Contact information is supplied as an existing Contact, PostGrid will not create a new Contact - simply reuse the one it already has.
But there are other ways to create a check. You can use the Contact IDs, like:
const postcard = await client.postcard.create({
description: 'Cool new check',
letterHTML: 'Hello {{to.firstName}}',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
bankAccount: 'bank_gMpKxPyiGzt1ZwACTmLHHn',
amount: 10000,
memo: 'Invoice 1233',
number: 9667,
})
so that if you know the created Contact data, you can just pass in the IDs. Of course, you can mix-and-match as well.
You can also use a standard Node Buffer
to load up the letter source:
import fs from 'fs'
const doc = fs.readFileSync('/my/local/file.pdf')
const postcard = await client.postcard.create({
description: 'Cool new check',
letterPDF: doc,
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
bankAccount: 'bank_gMpKxPyiGzt1ZwACTmLHHn',
amount: 10000,
memo: 'Invoice 1233',
number: 9667,
})
all of these are covered in the different forms of the PostGrid Create Cheque endpoints, but the Client detects the inputs and acts accordingly. You just have to provide the data.
As a final note, you can also pass in the optional Idempotency Key to the
create()
function, and this will have the added benefit that PostGrid will
not create a duplicate Check - within 24 hrs, of the initial create()
call
with the same idempotencyKey
. The key is provided in the call as an optional
second parameter:
const postcard = await client.postcard.create({
description: 'Cool new check',
letterHTML: 'Hello {{to.firstName}}',
to: 'contact_f8NLBJXjV82HnM8emVow3r',
from: 'contact_fo3HwdeFZ3wwNuHFAgszHt',
bankAccount: 'bank_gMpKxPyiGzt1ZwACTmLHHn',
amount: 10000,
memo: 'Invoice 1233',
number: 9667,
}, {
idempotencyKey: '9d972254-34eb-492e-90c2-739087a8487d'
})
where this example is just using a UUID.
Get a Check
const check = await client.check.get(id)
where id
is the Postcard ID, like cheque_7GrdUQPmbkAXJg8vLkJK9B
, in the
above example, and the response will be something like the response to the
client.check.create()
function.
List Checks
const checks = await client.check.list()
This will list all the Cheques/Checks assoiated with this API Key, and will
do so in the PostGrid List paging scheme of limit
and skip
. These
parameters are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"checks": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 3,
"data": [
{
"id": "cheque_1rLks7fM6nSC1jNpidv1fg",
"object": "cheque",
"live": false,
"amount": 10000,
"bankAccount": "bank_gMpKxPyiGzt1ZwACTmLHHn",
"currencyCode": "USD",
"description": "Cool new check",
"from": {
"id": "contact_fo3HwdeFZ3wwNuHFAgszHt",
"object": "contact",
"addressLine1": "123 MAIN STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "ATLANTA",
"companyName": "US Steel",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "John",
"lastName": "Quincy",
"postalOrZip": "12345",
"provinceOrState": "GA"
},
"letterHtml": "Hello {{to.firstName}}",
"memo": "Invoice 1233",
"number": 9667,
"sendDate": "2021-07-19T10:02:28.324Z",
"status": "ready",
"to": {
"id": "contact_f8NLBJXjV82HnM8emVow3r",
"object": "contact",
"addressLine1": "5454 WEST 34TH STREET",
"addressLine2": null,
"addressStatus": "verified",
"city": "INDIANAPOLIS",
"companyName": "Acme Rentals",
"country": "UNITED STATES",
"countryCode": "US",
"firstName": "Steve",
"lastName": "Smith",
"postalOrZip": "46224",
"provinceOrState": "IN"
},
"createdAt": "2021-07-19T10:02:28.327Z",
"updatedAt": "2021-07-19T10:02:28.327Z"
},
...
]
}
}
Progress a Test Cheque/Check
This function will move a Test Cheque/Check through the server-side processing steps, one at a time to allow the caller to verify the webhook calls. This is only available for Test Cheques/Checks.
const move = await client.check.progress(id)
where id
is the Cheque ID, like cheque_7GrdUQPmbkAXJg8vLkJK9B
, in the
above example, and the response will be similar to the response from
client.check.get(id)
.
Delete a Check
This function will delete - or Cancel a Cheque/Check that's not yet been sent.
const drop = await client.check.delete(id)
where id
is the Postcard ID, like cheque_7GrdUQPmbkAXJg8vLkJK9B
, in the
above example, and the response will be something like:
{
"success": true,
"check": {
"id": "cheque_7GrdUQPmbkAXJg8vLkJK9B",
"object": "cheque",
"deleted": true
}
}
Webhook Calls
The PostGrid Webhook is documented on this page and is the traditional way for an scynchronous service to alert the client that something has changed.
Create Webhook
The basic Create Webhook call looks something like this:
const letter = await client.webhook.create({
description: 'Cool new webhook',
url: 'https://my.service.com/postgrid/callback',
enabledEvents: ['letter.created'],
})
This will create the webhook back to the provided url
, and will then
be the notification system for any updates for the enabled events. The
response will be something like:
{
"success": true,
"webhook": {
"id": "webhook_wb6AAoBMcm1CNwWH3mkbr1",
"object": "webhook",
"live": false,
"description": "Cool new webhook",
"enabled": true,
"enabledEvents": [
"letter.created"
],
"secret": "webhook_secret_uAMxoCjLyHoCFWoA6XvhdC",
"url": "https://my.service.com/postgrid/callback",
"createdAt": "2021-07-15T20:11:51.032Z",
"updatedAt": "2021-07-15T20:11:51.032Z"
}
}
If there had been an error, the response would be:
{
"success": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Get a Webhook
const doc = await client.webhook.get(id)
where id
is the Letter ID, like webhook_wb6AAoBMcm1CNwWH3mkbr1
, in the
above example, and the response will be something like the response to the
client.webhook.create()
function.
List Webhooks
const doc = await client.webhook.list()
This will list all the Webhooks assoiated with this API Key, and will do so
in the PostGrid List paging scheme of limit
and skip
. These parameters
are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"webhooks": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 1,
"data": [
{
"id": "webhook_rqjK6m3T71butzwSd7zU4N",
"object": "webhook",
"live": false,
"description": "Cool new webhook",
"enabled": true,
"enabledEvents": [
"letter.created"
],
"secret": "webhook_secret_ve1xLLrBWRfDhjhNZZMRn3",
"url": "https://my.service.com/postgrid/callback",
"createdAt": "2021-07-15T20:14:11.060Z",
"updatedAt": "2021-07-15T20:14:11.060Z"
}
]
}
}
List Webhook Invocations
const doc = await client.webhook.invocations(id)
where id
is the Webhook ID, like webhook_rqjK6m3T71butzwSd7zU4N
, in the
above example. This will list all the Webhooks assoiated with this API Key,
and will do so in the PostGrid List paging scheme of limit
and skip
.
These parameters are optional, and if they are omitted, the defaults are:
-
skip
is0
-
limit
is40
The response will be something like:
{
"success": true,
"invocations": {
"object": "list",
"limit": 40,
"skip": 0,
"totalCount": 0,
"data": []
}
}
where, in this case, there have been no invocations on that webhook.
Delete a Webhook
This function will delete a Webhook that's currently being used for callbacks.
const doc = await client.webhook.delete(id)
where id
is the Letter ID, like webhook_rqjK6m3T71butzwSd7zU4N
, in the
above example, and the response will be something like:
{
"success": true,
"webhook": {
"id": "webhook_rqjK6m3T71butzwSd7zU4N",
"object": "webhook",
"deleted": true
}
}
Address Verification Calls
The PostGrid Address Verification is documented on this page and has both single, and batch address verification, City, State lookup from a Postal Code, and Address Suggestion endpoints.
Get Lookup Info
PostGrid allows some free address lookups, and this call is an easy call to make to get the status of those free lookups. The call looks something like this:
const info = await client.address.lookupInfo()
The response will be something like:
{
"success": true,
"info": {
"status": 'success',
"message": 'Successfully retrieved addver info.',
"data": { freeLimit: 500, used: 5 }
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Verify an Address
The PostGrid freeform address call allows the user to enter addresses like:
'2929 Eagledale Dr, Indianapolis, IN'
'3288 Tara Ln, Indianapolis, IN'
and so on. These will then be parsed, and verified, if possible by PostGrid. This function allows for both freeform addresses and structured addresses, of the form:
{
line1: '3288 Tara Ln',
city: 'Indianapolis',
postalOrZip: '46224',
provinceOrState: 'IN',
}
The basic call looks something like this:
const address = await client.address.verify('3288 Tara Ln, Indianapolis, IN')
or:
const address = await client.address.verify({
line1: '3288 Tara Ln',
city: 'Indianapolis',
postalOrZip: '46224',
provinceOrState: 'IN',
})
The response will be something like:
{
"success": true,
"verified": true,
"address": {
"status": 'success',
"message": 'Address verification processed.',
"data": {
"line1": '3288 Tara Ln',
"city": 'Indianapolis',
"provinceOrState": 'IN',
"postalOrZip": '46224',
"zipPlus4": '2231',
"country": 'us',
"countryName": 'UNITED STATES',
"errors": {},
"status": 'verified'
}
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Get Autocomplete Previews
Given just a street address, and an optional country
, the autocomplete
previews function will return a list of partial addresses of the form:
{
line1: string;
city?: string;
provinceOrState?: string;
}
This isn't strictly what is returned from PostGrid, but this client is trying to simplify the different data models on the return sets, so we have attempted to model it after the structured address as well.
The basic call looks something like this:
const list = await client.address.autocompletePreviews('77 main st')
The response will be something like:
{
"success": true,
"previews": {
"status": 'success',
"message": 'Retrieved verified address completions successfully.',
"data": [
{ "line1": '77 N MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 S MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 N MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 S MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 E MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 W MAIN ST', "city": undefined, "provinceOrState": 'UT' },
{ "line1": '77 N MAIN ST', "city": 'ABERDEEN', "provinceOrState": 'ID' },
{ "line1": '77 S MAIN ST', "city": 'ABERDEEN', "provinceOrState": 'ID' },
{ "line1": '77 N MAIN ST', "city": 'ABERDEEN', "provinceOrState": 'SD' },
{ "line1": '77 S MAIN ST', "city": 'ABERDEEN', "provinceOrState": 'SD' }
]
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Autocomplete an Address
Given an address, city and state - such as you'd get from a Preview, above, you can get the complete address with a call that looks something like this:
const info = await client.address.autocompleteAddress({
line1: '77 S MAIN ST',
city: 'ABERDEEN',
provinceOrState: 'SD',
})
The response will be something like:
{
"success": true,
"previews": {
"status": 'success',
"message": 'Retrieved verified address completions successfully.',
"data": [
{
line1: '77 S MAIN ST',
city: 'ABERDEEN',
provinceOrState: 'SD',
postalOrZip: '57401',
country: 'US'
}
]
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Batch Verify Addresses
Starting with either a freeform or structured address, this function can return each of the addresses, parsed - if necessary, and then individually verified, and tagged. The call can look something like this:
const info = await client.address.batchVerify([
'3288 Tara Ln, Indianapolis, IN 46224',
'3000 Tara Ln, Indianapolis, IN 46224',
{
line1: '77 S MAIN ST',
city: 'ABERDEEN',
provinceOrState: 'SD',
postalOrZip: '57401',
},
])
In this example, the middle address is not valid, and the response will be something like:
{
"success": true,
"addresses": {
"status": 'success',
"message": 'Verified address batch successfully.',
"data": [
{
"line1": '3288 Tara Ln',
"city": 'Indianapolis',
"postalOrZip": '46224',
"provinceOrState": 'IN',
"country": 'us',
"countryName": 'UNITED STATES',
"zipPlus4": '2231',
"status": 'verified',
"errors": {}
},
{
"line1": '3000 Tara Ln ',
"city": 'Indianapolis',
"postalOrZip": '46224',
"provinceOrState": 'in',
"status": 'failed',
"errors": {}
},
{
"line1": '77 S Main St',
"city": 'Aberdeen',
"postalOrZip": '57401',
"provinceOrState": 'SD',
"country": 'us',
"countryName": 'UNITED STATES',
"zipPlus4": '4218',
"status": 'verified',
"errors": {}
}
]
}
}
Where it's important to note that the status
of the middle Address in the
returned Array is 'failed'
- meaning taht the address provided could not
by verified.
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Suggest Addresses
At times, you may have an address, either freeform, or structured, that might not be exactly right, and you need to see if there are addresses that are close to that address - to see if you can find a match. This is the purpose of this function - to take an estimated address and return the nearest hits.
The call looks something like this:
const info = await client.address.suggestAddresses({
line1: '77 MAIN ST',
city: 'ABERDEEN',
provinceOrState: 'SD',
})
And the response will be something like:
{
"success": true,
"addresses": {
"status": 'success',
"message": 'Address suggestions retrieved successfully.',
"data": [
{
"city": 'Aberdeen',
"country": 'us',
"countryName": 'UNITED STATES',
"errors": {},
"line1": '77 N Main St',
"postalOrZip": '57401',
"provinceOrState": 'SD',
"status": 'verified',
"zipPlus4": '3428'
},
{
"city": 'Aberdeen',
"country": 'us',
"countryName": 'UNITED STATES',
"errors": {},
"line1": '77 S Main St',
"postalOrZip": '57401',
"provinceOrState": 'SD',
"status": 'verified',
"zipPlus4": '4218'
},
...
},
]
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Parse an Address
PostGrid can take a freeform address and simply parse it into it's components without verification, and the call looks something like this:
const info = await client.address.parseAddress('3288 Tara Ln, Indianapolis, IN 46224')
And the response will be something like:
{
"success": true,
"address": {
"status": 'success',
"message": 'Success.',
"data": {
"city": 'indianapolis',
"houseNumber": '3288',
"postcode": '46224',
"road": 'tara ln',
"state": 'in'
}
}
}
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Look up City/State from Postal Code
At times, you have the postal code, and need to know the city and state of that code. This function is designed for that, with a call that looks something like this:
const info = await client.address.lookupCityState('60540')
And the response will be something like:
{
"success": true,
"address": {
"status": 'success',
"message": 'Success.',
"data": {
"city": 'NAPERVILLE',
"provinceOrState": 'IL'
}
}
}
Where it's important to note that the status
of the middle Address in the
returned Array is 'failed'
- meaning taht the address provided could not
by verified.
If there had been an error, the response would be:
{
"success": false,
"verified": false,
"error": {
"type": "PostGrid_type",
"message": "(Error message from PostGrid...)"
}
}
Development
For those interested in working on the library, there are a few things that
will make that job a little simpler. The organization of the code is all in
src/
, with one module per section of the Client: contact
, letter
,
template
, etc. This makes location of the function very easy.
Additionally, the main communication with the PostGrid service is in the
src/index.ts
module in the fire()
function. In the constructor for the
Client, each of the sections are created, and then they link back to the
main class for their communication work.
Setup
In order to work with the code, the development dependencies include dotenv
so that each user can create a .env
file with a single value for working
with PostGrid:
-
POSTGRID_API_KEY
- this is the API Key referred to, above, and can be created on the PostGrid Dashboard page
Testing
There are several test scripts that create, test, and tear-down, state on the PostGrid service exercising different parts of the API. Each is self-contained, and can be run with:
$ npm run ts tests/contacts.ts
creating a single Contact...
Success!
fetching a single Contact...
Success!
listing the first page of 40 Contacts...
Success!
deleting a single Contact...
Success!
Each of the tests will run a series of calls through the Client, and check the
results to see that the operation succeeded. As shown, if the steps all
report back with Success!
then things are working.
If there is an issue with one of the calls, then an Error!
will be printed
out, and the data returned from the client will be dumped to the console.