NAV Navbar
shell javascript

Introduction

API Endpoint:

https://api.handwrite.io/v1/

Welcome to the Handwrite API!

You can use our API to send handwritten notes in an automated manner, using our REST endpoints.

We have language bindings in Shell and JavaScript, with Python and Ruby coming soon!

If you have questions or feedback please feel free to reach out to us here.

Getting Started

Handwrite uses API keys to allow access to the API. You must first sign up for a Handwrite account to obtain an API key. You will be charged per card based on the plan you choose.

Once you're logged in, you can create a key by going to the developer dashboard.

You'll notice when you create a key that it will start with test_hw or live_hw. Test keys will not count against your usage and can be used for testing purposes as you might have guessed!

An API key is expected to be included in all API requests to the server in a header that looks like the following:

Authorization: live_hw_sid92ldkasiie299dkw

Also, the content type must be Content-Type: application/json

Endpoints

Get Handwritings

The Request

curl --request GET \
  --url https://api.handwrite.io/v1/handwriting \
  --header 'authorization: test_hw_54838bde67e8e6255fa6' \
  --header 'content-type: application/json'
const request = require("request");

const options = {
  method: "GET",
  url: "https://api.handwrite.io/v1/handwriting",
  headers: {
    "content-type": "application/json",
    authorization: "test_hw_54838bde67e8e6255fa6"
  }
};

request(options, (error, response, body) => {
  if (error) throw new Error(error);

  console.log(body);
});

The Response - An array of handwriting objects in JSON format

[
  {
    "_id": "5db6f0724cc1751452c5ae8e",
    "name": "Jeremy",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270190/cards/wkwtnagsty79e0tlbiad.jpg"
  },
  {
    "_id": "5db6f08c4cc1751452c5ae8f",
    "name": "Tribeca",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270217/cards/hs92dvha3i5bvuhnboz7.jpg"
  },
  {
    "_id": "5db6f0f14cc1751452c5ae90",
    "name": "Terry",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270316/cards/bjocrcfhed6dwdadbtpv.jpg"
  }
]

This will fetch handwriting options for your users to preview and choose from.

Handwriting examples

HTTP Request

POST https://api.handwrite.io/v1/handwriting

Get Stationery

The Request

curl --request GET \
  --url https://api.handwrite.io/v1/stationery \
  --header 'authorization: test_hw_54838bde67e8e6255fa6' \
  --header 'content-type: application/json'
const request = require("request");

const options = {
  method: "GET",
  url: "https://api.handwrite.io/v1/stationery",
  headers: {
    "content-type": "application/json",
    authorization: "test_hw_54838bde67e8e6255fa6"
  }
};

request(options, (error, response, body) => {
  if (error) throw new Error(error);

  console.log(body);
});

The Response - An array of stationery objects in JSON format

[
  {
    "_id": "5db6f1854cc1751452c5ae93",
    "name": "Classic White",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270464/cards/yflijfai9wm38czthluk.jpg"
  },
  {
    "_id": "5db6f19b4cc1751452c5ae95",
    "name": "Classic Navy",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270484/cards/afwlmwfs4dkh5s6xt5uc.jpg"
  },
  {
    "_id": "5db6f1b74cc1751452c5ae96",
    "name": "Hello",
    "preview_url": "http://res.cloudinary.com/handwrite/image/upload/v1572270512/cards/mb9fhgwgnkdxiqtr9k0i.jpg"
  }
]

This will fetch any custom stationery you have uploaded as well as the publicly available options we provide.

Stationery examples

HTTP Request

GET https://api.handwrite.io/v1/stationery

Send a Letter

The Request

curl --request POST \
  --url https://api.handwrite.io/v1/send \
  --header 'authorization: test_hw_54838bde67e8e6255fa6' \
  --header 'content-type: application/json' \
  --data '{
  "message": "Hey dude,\nIt was great meeting you last week at the party. We'\''d love to have you back at the next one!\n\nBest,\n-Jackie",
  "handwriting": "5db6f0724cc1751452c5ae8e",
  "card": "5db6f0724cc1751452c5ae8e",
  "recipients": [
    {
      "firstName": "The",
      "lastName": "Dude",
      "company": "Unemployed",
      "street1": "25 Main Street",
      "city": "Los Angeles",
      "state": "CA",
      "zip": "90210"
    }
  ],
  "from": {
    "firstName": "Jackie",
    "lastName": "Treehorn",
    "street1": "1 Random Street",
    "street2": "Apt 33A",
    "city": "Malibu",
    "state": "CA",
    "zip": "90263"
  }
}'
const request = require("request");

const options = {
  method: "POST",
  url: "https://api.handwrite.io/v1/send",
  headers: {
    "content-type": "application/json",
    authorization: "test_hw_54838bde67e8e6255fa6"
  },
  body: {
    message:
      "Hey dude,\nIt was great meeting you last week at the party. We'd love to have you back at the next one!\n\nBest,\n-Jackie",
    handwriting: "5db6f0724cc1751452c5ae8e",
    card: "5db6f0724cc1751452c5ae8e",
    recipients: [
      {
        firstName: "The",
        lastName: "Dude",
        company: "Unemployed",
        street1: "25 Main Street",
        city: "Los Angeles",
        state: "CA",
        zip: "90210"
      }
    ],
    from: {
      firstName: "Jackie",
      lastName: "Treehorn",
      street1: "1 Random Street",
      street2: "Apt 33A",
      city: "Malibu",
      state: "CA",
      zip: "90263"
    }
  },
  json: true
};

request(options, (error, response, body) => {
  if (error) throw new Error(error);

  console.log(body);
});

The Response - An array of orders in JSON format

[
  {
    "_id": "5dba45e8f2b173cb5dff0300",
    "message": "Hey dude,\nIt was great meeting you last week at the party. We'd love to have you back at the next one!\n\nBest,\n-Jackie",
    "to": {
      "firstName": "The",
      "lastName": "Dude",
      "company": "Unemployed",
      "street1": "25 Main Street",
      "city": "Los Angeles",
      "state": "CA",
      "zip": "90210"
    },
    "from": {
      "firstName": "Jackie",
      "lastName": "Treehorn",
      "street1": "1 Random Street",
      "street2": "Apt 33A",
      "city": "Malibu",
      "state": "CA",
      "zip": "90263"
    },
    "status": "processing",
    "handwriting": "5db6f0724cc1751452c5ae8e",
    "card": "5db6f0724cc1751452c5ae8e",
    "createdAt": "2019-10-31T02:24:40.648Z"
  }
]

Send a letter to up to 10 recipients at once.

HTTP Request

POST https://api.handwrite.io/v1/send

Request parameters

Parameter Type Description
message required String This is the body of the letter. Maximum of 320 characters.
card required String ID of the stationery/card you want. This will also determine whether it is the front or back of card.
handwriting required String ID of the handwriting you want to use.
recipients required Array List of recipient objects. Must have at least one, but can be up to 10.
recipients[n].firstName String Recipient first name
recipients[n].lastName String Recipient last name
recipients[n].company String Recipient company. If this is included, company will be on the first line, with attention to on the second
recipients[n].street1 required String First line of the address, e.g. 555 Terrance Street
recipients[n].street2 String Second line of the address, e.g. Apt. 201
recipients[n].city required String
recipients[n].state required String *Must be the capitalized two digit abbreviation, e.g. AL instead of Alabama
recipients[n].zip required String Must be exactly 5 characters
from Object Return address. (optional)
from.firstName String
from.lastName String
from.street1 String
from.street2 String
from.city String
from.state String
from.zip String

Batch Mode

This endpoint also accepts an array, where each element is an object in the above format. The format of the response is the same as for sending a single message. A maximum of 1,000 individual orders (1 message x 1 recipient) may be submitted at a time.

Get an Order

The Request

curl --request GET \
  --url https://api.handwrite.io/v1/order/5f44086e69217700172ac110 \
  --header 'authorization: test_hw_54838bde67e8e6255fa6'
var request = require("request");

var options = {
  method: "GET",
  url: "https://api.handwrite.io/v1/order/5f44086e69217700172ac110",
  headers: { authorization: "test_hw_54838bde67e8e6255fa6" }
};

request(options, function(error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

The Response - An object in JSON format

{
  "_id": "5f44086e69217700172ac110",
  "message": "Hey there, hope all is well!",
  "status": "complete",
  "handwriting": "5dc30652bc08d20016f1ec33",
  "card": "5f33fde848cc140017f0364a",
  "createdAt": "2020-08-24T18:35:26.686Z",
  "environment": "live",
  "to": {
    "firstName": "Jamie",
    "lastName": "Stockton",
    "company": "Stockton Lumber",
    "street1": "8284 Random Road",
    "city": "Sarasota",
    "state": "FL",
    "zip": "34240"
  },
  "from": {
    "firstName": "Terrance",
    "lastName": "McGhee",
    "street1": "293 Hungerford Drive",
    "street2": "",
    "city": "Rockville",
    "state": "MD",
    "zip": "20850"
  },
  "proofs": [
    {
      "job_type": "card",
      "image_url": "https://s3.us-east-2.amazonaws.com/any-random-image.jpg"
    },
    {
      "job_type": "envelope",
      "image_url": "https://s3.us-east-2.amazonaws.com/another-random-image.jpg"
    }
  ]
}

This will allow you to fetch an order you've already placed whether it was from the web app or the API.

This will allow you to get the status of your order, which will be one of:

It will also allow you to access your proofs (visual images of your letter front and envelope) if the letter has been completed.

HTTP Request

GET https://api.handwrite.io/v1/order/:orderId

Rate Limiting

The Handwrite API is rate limited to prevent abuse that would degrade our ability to maintain consistent API performance for all users.

By default, each API key is rate limited at 60 requests per minute. If your requests are being rate limited, HTTP response code 429 will be returned with an rate_limit_exceeded error.

In your response headers, you should see information pertaining to your limits at any given time.

Header Description
X-RateLimit-Limit The maximum number of requests that the consumer is permitted to make per minute.
X-RateLimit-Remaining The number of requests remaining in the current rate limit window.
X-RateLimit-Reset The time at which the current rate limit window resets.

Response Codes

Handwrite uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted or was the incorrect type, etc.). Codes in the 5xx range indicate an error with our servers.

The Handwrite API uses the following response codes:

Error Code Meaning
200 Success. Everything worked as expected
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
404 Not Found -- The specified resource could not be found.
429 Too Many Requests -- You're requesting too much! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Third Party Packages

Many thanks to Tim Pile who created a library for using Elixir with the Handwrite API.

View Elixir Package on HexDocs