FORMAT: 1A
HOST: https://api2.autopilothq.com

# Autopilot REST API Documentation
Autopilot is easy-to-use software for multi-channel marketing. The Autopilot REST API allows you to:

- Send contacts from Autopilot to your app
- Add contacts from your app into Autopilot
- Trigger Autopilot journeys from your app
- Keep unsubscribes in sync between Autopilot and your app
- Enhance contact profiles with custom fields and data from your app
- Get data from your app into and out of Salesforce using Autopilot's native integration

Note that we also have a [Zapier integration](https://autopilothq.zendesk.com/hc/en-us/articles/204963625-How-to-use-Zapier-with-Autopilot), which enables simple integration of your Autopilot account with many web apps and CRMs that you are already familiar with. [Read more about our Zapier integration](https://autopilothq.zendesk.com/hc/en-us/articles/204963625-How-to-use-Zapier-with-Autopilotr).

# Getting Help

**How to log a support ticket**

If you need help, please [submit a ticket](https://autopilothq.zendesk.com/hc/en-us/requests/new) and our team will assist you.


# Group Authentication

## API Keys

Autopilot uses a custom header containing an API key to identify your requests. When Autopilot receives your request, it checks the API key to see if it is valid and matches an instance of Autopilot. If it does, your request is fulfilled.

## Getting an API key

To get an API key for your Autopilot account:

1. Login to your Autopilot account at https://login.autopilothq.com
2. Go to Settings 
3. Go to "Autopilot API"
4. Click "Generate"
5. Copy the API key

If you don't already have an Autopilot account, you can sign up for a free trial here [https://autopilothq.com](https://autopilothq.com)

## Protecting your API key

Your API key can be used to control your account, so you need to make sure that you protect it. Simple ways to avoid your API key being accessed by anyone else are:

* Always use HTTPS when accessing the Autopilot REST API (it is all we accept anyway)
* Do not send the API key over email
* Do not store the API key in your version control system

The safest way to use your API key is to store it in your database or on a file on your web server with 600 permission and access it at runtime in your application.

## Regenerating your API key

If your API key is every accidentally made public or put in a place where it could be accessed by an untrusted source, you can regenerate it to make a new one.

To do so:

1. Login to your Autopilot account at https://login.autopilothq.com
2. Go to the Settings section
3. Go to "API Keys"
4. Click "Regenerate"
5. Copy & Paste the API key

Note that this will cause your previous API key to stop working immediately.

## Using your API key

All Autopiliot API Methods require a header called `autopilotapikey` to be set in the HTTP request. All examples in this documentation contain an example of passing through this header in the various languages. If your header is set incorrectly you will receive a `400 Bad Request` to any request you send to the Autpilot API. If your API is invalid you will receive a `401 Unauthorized`.

# Group API Methods

Actions are API methods which allow you to actions in your Autopilot instance. Actions answer the question *"How do I get data into Autopilot and trigger journeys"*.

# Add/Update Contact [/v1/contact]

## Add or update contact [POST]

Autopilot has a standard set of fields which represent each contact. You are able to set any of these fields via this call. If a contact doesn't already exist, it will be created. If a contact with the same email address exists, it will be updated.

The standard Autopilot fields are these:

| Field Name | Required | Notes |
|---|---|---|
| contact_id | Auto | This field is automatically generated and used for contact operations |
| Email | No | Email is used to de-duplicate contacts |
| Twitter | No |   |
| FirstName | No |   |
| LastName | No |   |
| Salutation | No |   |
| Company | No |   |
| NumberOfEmployees | No |   |
| Title | No |   |
| Industry | No |   |
| Phone | No |   |
| MobilePhone | No |   |
| Fax | No |   |
| Website | No |   |
| MailingStreet | No |   |
| MailingCity | No |   |
| MailingState | No |   |
| MailingPostalCode | No |   |
| MailingCountry | No |   |
| owner_name | No |   |
| LeadSource | No |   |
| Status | No |   |
| LinkedIn | No |   |
| unsubscribed | No | Use this to unsubscribe or re-subscribe contacts. Send a boolean (true/false) value. |
| custom | No | See *Custom Fields* section below |
| _autopilot_session_id | No | Used to associate a contact with a session, see *Associating Sessions* below |
| _autopilot_list | No | Used to add this contact to a list upon creation, see *Add Contact to a List* below |
| notify | No | By default Autopilot notifies registered REST hook endpoints for `contact_added`/`contact_updated` when a new contact added or existing contact updated via API. Use this option to skip triggers.|

**Custom Fields**

Autopilot allows you to specify any fields you want as "custom fields". You do this by providing a 'custom' key in your JSON, you then need to format the custom variable names like so:

Let's say you had a variable called `Smog Level` which was an integer. You would provide it like so:

`{
    "Email": "chris@autopilothq.com",
    "custom": {
      "integer--Smog--Level": 4
    }
}`

The available types for custom variables are: `integer`, `float`, `boolean`, `date` and `string`.

[Read about the different Autopilot data types here](https://autopilot.docs.apiary.io/#reference/custom-field-data-types)

You may have noticed that a double dash, i.e. -- represents a space in the variable name.

The flexibility of adding any custom fields you want will mean that you can have your API enhance customer profiles in any way you choose.

Please note that the custom field name must be capitalized exactly like the custom field is in autopilot or a new custom field with the different capitalization will be automatically created.

So for example `integer--smog--level` will not update `Smog Level` while `integer--Smog--Level` will.

**Automatic adding of custom fields**

When you specify custom fields in the style described above, they will automatically be added to Autopilot as a custom field available throughout the system. Once a field has been added, it will be available to use in the UI to include in Emails, SMS, Postcards and anywhere else Autopilot variables are available including the contacts profile screen.

**De-duping contacts**

In Autopilot, we use the `Email` field as a unique identifier for contacts. Our primary key is `contact_id`, but we allow you to use these interchangeably in the API to make things easier. When adding a new contact, we use the `Email` address to de-duplicate contacts and identify when a contact needs to be *updated* rather than created. The *Updating Contacts* section below explains this behaviour.

**Changing a customer email address**

Since we use email address as the primary identifier for contacts in Autopilot, we do not allow you to update contacts via the regular `Email` field. This is because providing a unique email in that field would simply create a new contact.

For that reason we have a special field called `_NewEmail` which, if provided, will change the email address of the contact identified by the `Email` field.

For example:

`{
    "Email": "chris@autopilothq.com",
    "_NewEmail": "christopher@autopilothq.com"
}`

This would change the contact's email address from "chris@autopilothq.com" to "christopher@autopilothq.com". All history and other information for this contact will be retained.

*Note:* if you try to change a contact's email address to an email which already exists, you will receive a 409 Conflict error or in some cases a 500 error.

**Updating Contacts**

You will notice that we do not have an "Update Contact" method in the Autopilot API. This is because the "Add Contact" method is also the way to update contacts. When you call the add contact API method and provide contact details where a contact with that `Email` already exists, the system will *overwrite* the existing data with the new data.

The merge strategy is as follows:

- `Email` is used as the uniquely identifying property of a contact.
- Fields provided which already exist will be overwitten.
- Fields set to `null` will have their values cleared.

Note that Email is not a required field, but if you don't provide it, it will be possible to create duplicates in the system.


**Associating Sessions**

If you're using Autopilot's [Tracking Code](https://autopilothq.zendesk.com/hc/en-us/articles/203881275-Tracking-visitors-to-your-website-and-blog), you can associate a visitor session to a contact with the special contact field `_autopilot_session_id`.

    {
      "Email": "george@autopilothq.com",
      "FirstName": "George",
      "_autopilot_session_id": "4ne73uvpS4ek54ryvOZtJ0PSBZNd8UW4moQn9lt9bqA"
    }

There are two ways to find the session id, by adding a special field to your forms, or by writing your own Javascript.

***Finding the session id with a special form field***

The Autopilot tracking code will populate any empty, hidden form field with the name `_autopilot_session_id` allowing you to capture the session id from any form submission.

To use this method, insert this hidden field into your form:

    <input type="hidden" name="_autopilot_session_id" />

For example:

    <form method="POST" action="http://example.com/my-submit-handler">
      <input type="hidden" name="_autopilot_session_id" />
      <p>Email: <input type="email" name="email" /></p>
      <p><input type="text" name="firstname" /></p>
      <p><input type="text" name="lastname" /></p>
      <p><input type="submit" /></p>
    </form>

Note that the input must be `type="hidden"`, and must not have a `value=` attribute.

When the form is submitted to your server, it will contain an `_autopilot_session_id` parameter with the session id.

***Finding the session id with javascript in the browser***

In any page with the Autopilot tracking code installed, you can access the session id directly:

    var sessionId = AutopilotAnywhere.sessionId;

This allows your javascript code to capture the Autopilot session id.

**Add Contact to a list**

It is possible to add a contact and add them to a list in a single API call, you just need to provide an additional contact field called _autopilot_list with the list id, e.g.

"_autopilot_list": "contactlist_91053049-5582-40B4-A17F-78ADF8F25663"

You can obtain the list name with the fetch lists command documented in this API, or through the URL bar in your browser when viewing the list in Autopilot.

If you provide this along with the request it will both add the contact and add them to the list.

**Return value**

The JSON object returned by the system will provide a `contact_id`. You will need this for future operations on contacts, although we do allow you to use email address in most cases.


+ Request

   + Parameters

            + contact (object) ... A JSON object containing contact fields as described above.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            {
                "contact": {
                    "FirstName": "Slarty",
                    "LastName": "Bartfast",
                    "Email": "test@slarty.com",
                    "custom": {
                        "string--Test--Field": "This is a test"
                    }


              }

            }

+ Response 200 (application/json)

        {"contact_id": "person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No contact details provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Bulk add Contacts [/v1/contacts]

## Bulk add contacts [POST]

If you are using the Autopilot API to add or update a large amount of contacts, using the bulk add contacts method
will be more efficient. This method allows you to add batches of contacts up to 100 at a time.

Autopilot has a standard set of fields which represent each contact. You are able to set any of these fields via this call. If a contact doesn't already exist, it will be created. If a contact with the same email address exists, it will be updated.

Your provide a list of contacts in your JSON request inside a key called CONTACTS. Each of the contacts can have any or all of the fields below, including custom fields.

The standard Autopilot fields are these:

| Field Name | Required | Notes |
|---|---|---|
| Email | Yes | Email is used to de-duplicate contacts |
| Twitter | No |   |
| FirstName | No |   |
| LastName | No |   |
| Salutation | No |   |
| Company | No |   |
| NumberOfEmployees | No |   |
| Title | No |   |
| Industry | No |   |
| Phone | No |   |
| MobilePhone | No |   |
| Fax | No |   |
| Website | No |   |
| MailingStreet | No |   |
| MailingCity | No |   |
| MailingState | No |   |
| MailingPostalCode | No |   |
| MailingCountry | No |   |
| owner_name | No |   |
| LeadSource | No |   |
| Status | No |   |
| LinkedIn | No |   |
| unsubscribed | No | Use this to unsubscribe or re-subscribe contacts. Send a boolean (true/false) value. |
| custom | No | See *Custom Fields* section below |
| _autopilot_session_id | No | Used to associate a contact with a session, see *Associating Sessions* below |
| notify | No | By default Autopilot notifies registered REST hook endpoints for `contact_added`/`contact_updated` when a new contact added or existing contact updated via API. Use this option to skip triggers.|

**Custom Fields**

Autopilot allows you to specify any fields you want as "custom fields". You do this by providing a 'custom' key in your JSON, you then need to format the custom variable names like so:

Let's say you had a variable called `Smog Level` which was an integer. You would provide it like so:

`{
    "email": "chris@autopilothq.com",
    "custom": {
      "integer--Smog--Level": 4
    }
}`

The available types for custom variables are: `integer`, `float`, `boolean`, `date` and `string`.

The flexibility of adding any custom fields you want will mean that you can have your API enhance customer profiles in any way you choose.

**De-duping contacts**

In Autopilot, we use the `Email` field as a unique identifier for contacts. Our primary key is `contact_id`, but we allow you to use these interchangeably in the API to make things easier. When adding a new contact, we use the `Email` address to de-duplicate contacts and identify when a contact needs to be *updated* rather than created. The *Updating Contacts* section below explains this behaviour.

**Updating Contacts**

You will notice that we do not have an "Update Contact" method in the Autopilot API. This is because the "Add Contact" method is also the way to update contacts. When you call the add contact API method and provide contact details where a contact with that `Email` already exists, the system will *overwrite* the existing data with the new data.

The merge strategy is as follows:

- `Email` is used as the uniquely identifying property of a contact.
- Fields provided which already exist will be overwitten.

This will apply individually for each of the contacts. However please note that since we use a clustered system, if you provide duplicates in the same
group of contacts, they may be missed by the system due to timing.

**Return value**

The JSON object returned by the system will provide an array of `contact_ids`.
These ids will not necessarily be in the same order as the contacts you provided in your request.
We also include a "email_contact_map" key in the JSON response which will map the email address of the contacts you added or updated to their Autopilot contact_ids. This gives you a way to easily figure out the Autopilot contact_id based on a contact's email address.

+ Request

   + Parameters

            + contacts (object) ... A JSON array of JSON objects containing contact fields as described above.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            {
                "contacts": [
                    {
                        "FirstName": "Slarty",
                        "LastName": "Bartfast",
                        "Email": "test@slarty.com",
                        "custom": {
                            "string--Test--Field": "This is a test"
                        }
                    },
                    {
                        "FirstName": "Jerry",
                        "LastName": "Seinfeld",
                        "Email": "jerry@seinfeld.com"
                    },
                    {
                        "FirstName": "Elaine",
                        "LastName": "Benes",
                        "Email": "elaine@seinfeld.com"
                    }
                ]

            }

+ Response 200 (application/json)

        {"contact_ids": ["person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7", "person_9EAF39E4-9AEC-4134-964A-D9D8D5416AAA"],"email_contact_map": {"chris@autopilothq.com": "person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7", "peter@autopilothq.com":"person_9EAF39E4-9AEC-4134-964A-D9D8D5416AAA"}}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No contacts provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 413 (application/json)

        {"error": "Request Entity Too Large", "message": "Please limit bulk requests to 100 contacts or less."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Get all contacts [/v1/contacts/{bookmark}]

## Get all contacts [GET]

This method will return a list of all of the contacts for your account.

You will be given a JSON object with 2 or 3 properties as a reply:

 - `total_contacts`: the total number of contacts
 - `contacts`: the current batch of 100 contacts
 - `bookmark`: if there are more contacts on the list than have been returned, the bookmark will allow you to access the next group of contacts.

To get the next group of contacts, provide the bookmark extracted from the previous result in the path to this call:

`GET https://api2.autopilothq.com/v1/contacts/person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`

For your initial call, you will not have a bookmark, so just leave off the last part of the URL:

`GET https://api2.autopilothq.com/v1/contacts`


+ Request

   + Parameters

            + bookmark (string) ... Optional, extracted from the previous result, this will allow you to "page through" the contacts on a list.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "contacts": [
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "red",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact",
                "LastName": "contact",
                "FirstName": "example",
                "Email": "email@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              },
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "blue",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact2",
                "LastName": "contact2",
                "FirstName": "example",
                "Email": "email2@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              }
            ]
            "total_contacts": 400,
            "bookmark": "person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7"
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Contact Operations [/v1/contact/{contact_id_or_email}]

## Get contact [GET]

This method retrieves the given contact record. You can provide either a contact_id which looks like `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7` or an email address. If you would like to see the fields which will be returned in the contact record, read the "Add Contact" section above.

Note that there will probably be fields on contact records which are not described above, many of these are used internally by the Autopilot system but are not directly editable by Autopilot users. You are welcome to use these values, but will not be able to change them. Please see the "Custom Fields" section if you need other fields to work with.

We currently do not support bulk operations for retrieving large amounts of contacts in a more efficient way. We will be adding this to our API in the future.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "contact_id":"person_AP2-9cbf7ac0-eec5-11e4-87bc-6df09cc44d23",
            "FirstName":"Chris",
            "LastName":"Sharkey",
            "type":"Contact",
            "Email":"chris@autopilothq.com",
            "Phone":"4159945916",
            "created_at":"2015-04-29T23:15:25.347Z",
            "updated_at":"2015-04-29T23:15:25.347Z",
            "LeadSource":"Autopilot",
            "Status":"Testing",
            "Company":"Magpie API",
            "lists":["contactlist_9EAF39E4-9AEC-4134-964A"]
        }

+ Response 404 (application/json)

        {"error": "Not Found", "message": "Contact could not be found."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid contact_id_or_email value provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

## Delete a contact [DELETE]

This method will remove the contact from your database and stop them from continuing in any journeys, being in any segments or lists, and receiving emails, SMS and other communications.

Deleting a contact is permanent, and there is no way to undo it. At Autopilot we keep backups on an daily, weekly and monthly basis, but we still encourage you to be careful when deleting data via the API.

To delete a contact you need to provide the `:contact_id_or_email` parameter. This allows you to specify an Autopilot `contact_id` such as `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7` or an email address. If there is more than one contact with that email address in the database, the first contact which matches will be deleted.

On success you will receive a `200 OK` response. If the contact you are trying to delete doesn't exist because they have already been deleted, or never existed, you will receive a `404 Not Found` response.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

+ Response 403 (application/json)

        {"error": "Forbidden", "message": "Could not delete contact as it is sycned with Salesforce."}

+ Response 404 (application/json)

        {"error": "Not Found", "message": "Contact could not be found."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid contact_id_or_email value provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Unsubscribe contact [/v1/contact/{contact_id_or_email}/unsubscribe]

## Unsubscribe contact [POST]

This method will unsubscribe the contact from receiving emails from your Autopilot Journeys. On success you will receive a `200 OK` response. If the contact you are trying to delete doesn't exist because they have already been deleted, or never existed, you will receive a `404 Not Found` response.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

+ Response 404 (application/json)

        {"error": "Not Found", "message": "Contact could not be found."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid contact_id_or_email value provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Trigger Journey [/v1/trigger/{trigger_id}/contact/{contact_id_or_email}]

## Add a contact to a journey [POST]

If you wish to add a contact to a particular Autopilot journey, you can do so by adding an API Trigger to your journey. To do this, login to the Autopilot admin and look for the API Trigger, and drag it onto the Journey canvas. You will note that it assigned a number to the trigger such as `0001`.

Once you publish the journey, this trigger can now be activated via the API using this method.

As with other API calls, we provide you with the ability to provide either an Autopilot `contact_id` or an email address as the `contact_id_or_email` parameter. If you provide an email address, any contact with  that email address will be added to the journey, however due to us merging/de-duping contacts based on email address, it is unlikely that there will ever be more than one contact with a given email address.

If you want to add the contact and trigger the journey in one go, you can do that too. Just leave off the `/contact_id_or_email` part of the URL, and provide a `contact` key as described in the `Add Contact` section of this document.

Additionally you need to provide the trigger_id which is the number you saw on the API Trigger, e.g. `0001`.

If the `trigger_id` does not exist, or the contact does not exist, you will receive a `404` status in the response.

+ Request

   + Parameters

            + trigger_id (string) ... Described above e.g. `0001`.
            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

+ Response 404 (application/json)

        {"error": "Not Found", "message": "Could not delete the contact from the journey as the journey could not be found."}

+ Response 404 (application/json)

        {"error": "Not Found", "message": "Could not delete the contact from the journey as the contact was not on that journey."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Get list of journeys containing API triggers [/v1/triggers]

## Get list of journeys with API triggers [GET]

If you are triggering journeys from API calls (see above: "Add a contact to a journey") you may need a way to programmatically get a list of published journeys which contain an API trigger.

Each API trigger has a unique, sequential ID to identify it and these are used when triggering the journey. Calling this method will give you a list of these along with the journey name to help you identify the correct one.

`triggerType` is included to help you identify custom application triggers. These will be part of our custom integrations with partners so as a regular API user you will always see "apiTrigger".

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "triggers":

                [

                    {"trigger_id":"0001","journey":"5-day Drip Nurture","triggerType":"apiTrigger"},{"trigger_id":"0002","journey":"Hot Leads Journey","triggerType":"apiTrigger"}

                ]

        }
+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}



# Lists [/v1/lists]

## Get list of lists [GET]

This method will get you a list of all available lists which you can add contacts to, remove contacts from or get a list of contacts on.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "lists":

                [

                    {"list_id":"contactlist_06444749-9C0F-4894-9A23-D6872F9B6EF8","title":"1k.csv"},{"list_id":"contactlist_0FBA1FA2-5A12-413B-B1A8-D113E6B3CDA8","title":"____NEW____"}

                ]

        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# List Operations [/v1/list]

## Add list [POST]

Lists are used in Autopilot to group contacts together. A contact can belong to as many lists as you like. This method allows you to add a new list. It will appear in the tree in the Contacts section of Autopilot, and you can use the returned `list_id` to add any contacts you like to it by using the "Add Contacts To List" method.

Note that unless the request is malformed, you should always get a successful response when adding a list. If you specify a list name which already exists, a sequential number will be added to the end of the list name. For example if you passed through `name` as "Test List" and "Test List" already exists, a new list will be created called "Test List 2", and this will be returned as the `name` property in the response.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            { "name": "Test list" }

+ Response 200 (application/json)

        { "list_id": "contactlist_98a45928946bc74e8a5c8c2d7ba30fefe7fd7445", "name": "Test List 2" }

+ Response 400 (application/json)

        {"error": "Conflict", "message": "Invalid data provided to add list."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Get contacts on list [/v1/list/{list_id}/contacts/{bookmark}]

## Get contacts on list [GET]

This method will return a list of all of the contacts which are on this list. It does not support smart segments.

Note if you are copying and pasting a list_id from the Autopilot UI (it appears in the URL when you view a list), you need to add a contactlist_ prefix to the ID. `list_id` values always start with contactlist_.

You will be given a JSON object with 2 or 3 properties as a reply:

- `total_contacts`: the total number of contacts in this batch
- `contacts`: the current batch of contacts
- `bookmark`: if there are more contacts on the list than have been returned, the bookmark will allow you to access the next group of contacts

To get the next group of contacts, provide the bookmark extracted from the previous result in the path to this call:

`GET https://api2.autopilothq.com/v1/list/contactlist_F342AF0A-1916-43AE-8F06-3F78DD/contacts/person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`

For your initial call, you will not have a bookmark, so just leave off the last part of the URL:

`GET https://api2.autopilothq.com/v1/list/contactlist_F342AF0A-1916-43AE-8F06-3F78DD/contacts`

Here is a blog post on how to use this method, with examples: [Getting contacts on a list with bookmarks](http://developers.autopilothq.com/getting-contacts-on-a-list-with-bookmarks.html)

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.
            + bookmark (string) ... Optional, extracted from the previous result, this will allow you to "page through" the contacts on a list.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {

            "contacts": [
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "red",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact",
                "LastName": "contact",
                "FirstName": "example",
                "Email": "email@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              },
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "blue",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact2",
                "LastName": "contact2",
                "FirstName": "example",
                "Email": "email2@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              }
            ]
            "total_contacts": 2,
            "bookmark": "person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7"
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Contact list operations [/v1/list/{list_id}/contact/{contact_id_or_email}]

## Check if contact is on list [GET]

Use this method to check if a contact belongs to a particular list.

Note if you are copying and pasting a list_id from the Autopilot UI (it appears in the URL when you view a list), you need to add a contactlist_ prefix to the ID. `list_id` values always start with contactlist_.

A `200` response code means that the contact is on the list, a `404` means that the contact cannot be found, or is not on the list.

+ Request

   + Parameters

            + list_id (string) ... A list_id e.g. `contactlist_9EAF39E4-9AEC-4134`.
            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {}

+ Response 404 (application/json)

        {"error": "Not Found"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

## Add contact to list [POST]

Use this method to add a contact to a list. If the contact was already on the list, the JSON response will be of status `200`, but contain `not_modified: true`.

Note if you are copying and pasting a list_id from the Autopilot UI (it appears in the URL when you view a list), you need to add a contactlist_ prefix to the ID. `list_id` values always start with contactlist_.

+ Request

   + Parameters

            + list_id (string) ... A list_id e.g. `contactlist_9EAF39E4-9AEC-4134`.
            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {"not_modified": true}

+ Response 404 (application/json)

        {"error": "Not Found"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

## Remove contact from list [DELETE]

Use this method to remove a contact from a list. A `200` response means that the contact was removed from the list. If the contact wasn't on the list, the JSON response will be of status `200`, but contain `not_modified: true`.

Note if you are copying and pasting a list_id from the Autopilot UI (it appears in the URL when you view a list), you need to add a contactlist_ prefix to the ID. `list_id` values always start with contactlist_.

+ Request

   + Parameters

            + list_id (string) ... A list_id e.g. `contactlist_9EAF39E4-9AEC-4134`.
            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {}

+ Response 404 (application/json)

        {"error": "Not Found"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Smart Segments [/v1/smart_segments]

## Get list of smart segments [GET]

This method will get you a list of all available smart segments.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
          "segments": [
            {
              "segment_id": "contactlist_sseg1456891025207",
              "title": "Ladies"
            },
            {
              "segment_id": "contactlist_sseg1457059448884",
              "title": "Gentlemen"
            }
          ]
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Get contacts on smart segment  [/v1/smart_segments/{smart_segment_id}/contacts/{bookmark}]

## Get contacts on smart segment [GET]

This method will return a list of all of the contacts which are on this smart segment. It does not support lists.

Note if you are copying and pasting a smart_segment_id from the Autopilot UI (it appears in the URL when you view a smart segment), you need to add a contactlist_ prefix to the ID. `smart_segment_id` values always start with contactlist_sseg.

You will be given a JSON object with 2 or 3 properties as a reply:

- `total_contacts`: the total number of contacts on this smart segment
- `contacts`: the current batch of 100 contacts
- `bookmark`: if there are more contacts on the list than have been returned, the bookmark will allow you to access the next group of contacts.

To get the next group of contacts, provide the bookmark extracted from the previous result in the path to this call:

`GET https://api2.autopilothq.com/v1/smart_segments/contactlist_sseg1461960501606-1F3E6060-0E46-11E6-B9C5-1B11C098EFAC/contacts/person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`

For your initial call, you will not have a bookmark, so just leave off the last part of the URL:

`GET https://api2.autopilothq.com/v1/smart_segments/contactlist_sseg1461960501606-1F3E6060-0E46-11E6-B9C5-1B11C098EFAC/contacts`

Note that unlike the related call to get contacts from a list, these bookmarks will expire after a set time and in rare circumstances can become invalidated by changes to your contacts. Already consumed bookmarks expire much faster than bookmarks that have not yet been used.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.
            + bookmark (string) ... Optional, extracted from the previous result, this will allow you to "page through" the contacts on a list.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "contacts": [
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "red",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact",
                "LastName": "contact",
                "FirstName": "example",
                "Email": "email@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              },
              {
                "custom_fields": [
                  {
                    "kind": "color",
                    "value": "blue",
                    "fieldType": "string"
                  }
                ],
                "company_priority": false,
                "Name": "example contact2",
                "LastName": "contact2",
                "FirstName": "example",
                "Email": "email2@domain.com",
                "Company": "Example inc",
                "lists": [
                  "contactlist_A05E722F-D78B-4F07-8F85-765AAED99D1D"
                ],
                "created_at": "2016-07-21T19:54:04.000Z",
                "updated_at": "2020-05-05T20:50:46.000Z",
                "contact_id": "person_00E0F208-DBD4-494E-9BBD-A27A8A721D02"
              }
            ]
            "total_contacts": 400,
            "bookmark": "person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7"

        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Provided bookmark has expired or is invalid"}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Contact Custom Fields [/v1/contacts/custom_fields]

## Get Custom Fields [GET]
Use this method to get a list of all custom fields.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800


+ Response 200 (application/json)

        [
          {
            "fieldType": "string",
            "key": "contacts_customfields_1456200756325_ab876950-d9e3-11e5-b21c-31af5a6619a2",
            "name": "visitedCities"
          },
          {
            "fieldType": "string",
            "key": "contacts_customfields_1456200763929_b00fb090-d9e3-11e5-b21c-31af5a6619a2",
            "name": "visitedCountries"
          }
        ]


# Account Operations [/v1/account]

## Get account [GET]

This method retrieves the account information of the primary account holder of the Autopilot instance associated with the provided API key.

If you are just using the API for your own instance, this method will be useless to you! But if you are making an app which allows multiple
Autopilot users to use your app by providing their API key, this is how you will identify who that user is, and their associated data.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "at": 1433371195830,
            "businessName": "Autopilot",
            "fullName": "Chris Sharkey",
            "firstName": "Chris",
            "lastName": "Sharkey",
            "email": "chris@autopilothq.com",
            "mobile": "+14159945999"
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Email Operations [/v1/email/{email_id}]

## Get email [GET]

This method retrieves an email campaign's data based on an ID received in the Autopilot Activity Stream. 

If you do not have Activity Streams set up find out more here: [https://blog.autopilothq.com/introducing-activity-streams-autopilot/](https://blog.autopilothq.com/introducing-activity-streams-autopilot/)

+ Request

   + Parameters

            + email_id (string) ... The email ID received in the activity stream.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
          "campaign": "1422223752755-95657030-99d5-11e4-ae56-766a90642f87",
          "author": "Michael Sharkey",
          "subject": "Weekly Team Update",
          "from_name": "Michael Sharkey",
          "reply_to": "mike@autopilothq.com",
          "subject": "Weekly Team Update",
          "author": "Michael Sharkey",
          "status": "Live",
          "mail_html": "<html><body>Markup for email goes here</body><html>",
          "variables": [
            "redirect_url-1",
            "redirect_url-2"
          ],
          "urls": [
            "https://www.youtube.com/watch?v=7ugMu1szUcw",
            "https://sites.google.com/a/bislr.com/intranet/airport-lounge"
          ],
          "replace_variables": {}
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid email_id provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "400: Invalid email_id provided, no prefix needed."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 404 (application/json)

        {"error": "Not Found", "message": "404: Email campaign not found."}

+ Response 404 (application/json)

        {"error": "Not Found", "message": "404: Email campaign not published."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Page visit - record visit [/v1/pagevisit/visit]

The Autopilot tracking code is a script tag which allows you to track all of the visitors to your website. It allows you to track visitors both known and unknown, and then once it does know who someone is (say they fill in a form or click a link in an email), it can then go back and associate those visits with that contact. In this way you are able to see the history of the pages a contact has viewed, or segment contacts based on this information.

## Record page visit [POST]

Sometimes it isn't possible for you to be able to include the Autopilot script tag on your website, so this endpoint allows you to record a page visit programmatically using your own sessionId, which you can then use later with the /v1/pagevisit/associate endpoint to associate that session with a particular contact once you know who it is. Please note, page visits recorded in this way will not associate except by using the associate session API call even if you use the Autopilot sessionId for the sessionId property of this call as the sessionId in this call is presumed to be your own unique session identifier. Currently page visits recorded and associated this way will not be associated automatically on new visits after the last associate call, so you should call associate after each visit that is recorded in this way.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            { "sessionId": "2b71ada6df1cfb85572a05f7ebedf814", "url": "http://www.mywebsite.com/page14" }

+ Response 200 (application/json)

        { }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "400: sessionId is required"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "400: url is required"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Page visit - associate session [/v1/pagevisit/associate]

## Associate session [POST]

If you have been recording website visits with the /v1/pagevisit/visit endpoint then you need to also associate those sessionIds with an email address. This will allow the system to associate the recorded page visits with the correct contact in the system.

In Autopilot we do this by email address.

Once you use the associate session, all website visits recorded under that sessionId (which have already occurred) will be associated with the contact who has that email address. You will need to run this method again to associate future events. Note that if a contact with that email address does not exist, it will be created. This contact will ONLY have an email address so will appear in the activity feed as "Someone". To add more details to contacts via the API use the POST /v1/contact endpoint.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            { "sessionId": "2b71ada6df1cfb85572a05f7ebedf814", "email": "sally@autopilothq.com" }

+ Response 200 (application/json)

        { }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "400: sessionId is required"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "400: email is required"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Delete contact activity feed [/v1/contact/{contact_id_or_email}/activityfeed/{type_of_activities}]

## Delete contact activity feed [DELETE]

This method was added to help Autopilot customers comply with GDPR deletion requests. Calling this method with the contact_id or email address of the customer will result in their entire activity feed being deleted.

If you just delete a contact normally in Autopilot or via the API, their activity feed is deleted too. This is for the case where you want to *only* delete their activity feed, but keep the contact record.

Note that depending on the amount of activities this customer has, this operation may take up to a few minutes to complete. This might mean you get a queued response from the API, and the operation wil be completed within a few minutes.

It is also possible to just specify a type of activity you could like to remove. For example, in the case that someone just wants website traffic visits deleted.

- `all` will delete all activities for this contact, and if you want to delete the whole activity feed, this is required.
- `pagevisits` will delete all website visit activity for this contact.

You must specify one of these in the URL.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.
            + type_of_activities ... Either `all` or `pagevisits` depending on which activities you want to delete for this contact.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            {}

+ Response 200 (application/json)

        {}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid data provided."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}




# Group REST Hooks

REST Hooks answer the question: *What events can I listen for coming out of Autopilot?*

A REST Hook event is fired any time an event listed below happens, for which you have a "REST Hook" set up. A REST Hook is a URL endpoint which you provide using the `/v1/hook` method, it will have data POSTed to it when the event occurs.

# Register REST Hook [/v1/hook]

## Register a REST Hook [POST]

Rather than having your system continuously poll to find out when there is new information to trigger from, we allow you to register a URL which we will call when these events occur, called a "REST Hook". Whenever an event you have registered for occurs, for example a new contact being added to Autopilot, we will send a HTTP POST to your URL with information about that event for your system to act upon.

The **triggers** section of this document describes the available events and the data which they will send through, the currently supported triggers are:

- `contact_added`
- `contact_updated`
- `contact_unsubscribed`
- `contact_added_to_list`
- `contact_removed_from_list`
- `contact_entered_segment`
- `contact_left_segment`

Descriptions of the data provided by each of these events is in the next section of this document below.

To register a new REST Hook, you need to sent a post request to `/v1/hook`, with the following parameters:

- `event` - This is the trigger event name that you wish to be told about.
- `target_url` - This is the URL in your API which you want our API to POST to when this event occurs.

When you request is valid, you will receive a *201 Created* status. From this point on, when the event you register for happens, your URL will be POSTed to with the event data. Please read the relevant **trigger** section to see the data which you will receive.

You may register more than one `target_url` for a given event, when the event occurs *each* of the registered target URLs will be called with the event data. You may not, however, register the same `target_url` more than once, if you try you will receive a *409 Conflict*.

When your `target_url` is POSTed to, our system will react in different ways depending on how your system responds:

1. If we gets a `410 Gone`, we will delete your REST Hook from our system and not call it again.
2. If we get a timeout, we will try again up to 5 times, using an incremental backoff, eventually giving up.
3. If we get a status which **is not** between `200-204`, we will try again up to 5 times, using an incremental backoff, eventually giving up.
4. If we get a status which **is** between `200-204`, then we have a successful call.

In cases **2.** and **3.**, once the request has failed 5 retries, then the trigger event is lost and will not be replayed. If is your responsibility to make sure that once registered, your target URL is successfully responding. If your system has trouble staying online, or keeping up with the pace of requests, then a good design pattern is to have a dedicated service to receive and buffer the requests to a volatile (Redis) or non-volatile (Postgresql, MongoDB) database, and then have a second service which picks up those requests and processes them at a pace which your system can handle.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800
            Content-Type: application/json

   + Body

            {
                "event": "contact_added",
                "target_url": "https://myapi.mycompany.com/ap14112546"
            }

+ Response 201 (application/json)

        {"id": "hook_ED75BA78-2405-4564-B24C-F2B8F936C7C6"}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid data provided to register REST Hook."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid event provided to register REST Hook."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid target_url provided to register REST Hook."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# Unregister REST Hook [/v1/hook/{hook_id}]

## Unregister a REST Hook [DELETE]

When you no longer wish your `target_url` to be POSTed to when the registered Autopilot event happens, you may unsubscribe an endpoint URL by providing the `hook_id` which was given to you when you registered.

If you no longer have the `hook_id` available, use the "Get REST Hooks" command (GET /v1/hooks) to get a list of registered hooks.

+ Request

   + Parameters

            + contact_id_or_email (string) ... Either the Autopilot contact_id e.g. `person_9EAF39E4-9AEC-4134-964A-D9D8D54162E7`, or the contact's email address.

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "Invalid data provided to unregister REST Hook."}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

# List or Delete REST Hooks [/v1/hooks]

## List REST Hooks [GET]

Rather than having your system continuously poll to find out when there is new information to trigger from, we allow you to register a URL which we will call when these events occur, called a "REST Hook". Whenever an event you have registered for occurs, for example a new contact being added to Autopilot, we will send a HTTP POST to your URL with information about that event for your system to act upon.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {
            "hooks":

                [
                    {
                        "hook_id": "hook_contact_added_7b804a954931111da7d3c3ccf8ba18b4e62bc949",
                        "event": "contact_added",
                        "target_url": "http://api1.bislr.net:9001/event_contact_added",
                        "created_at": 1430525435054
                    }
                ]
        }

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}

## Delete all REST Hooks [DELETE]

If you have a situation where you wish to delete all of your REST Hooks at the same time, this method is your answer. Calling this will delete all REST Hooks and we will stop hitting your end points when events occur.

+ Request

   + Headers

            autopilotapikey: 65263027fab7d440ba4c5f3b834fb800

+ Response 200 (application/json)

        {}

+ Response 400 (application/json)

        {"error": "Bad Request", "message": "No autopilotapikey header provided."}

+ Response 401 (application/json)

        {"error": "Unauthorized", "message": "Provided autopilotapikey not valid."}

+ Response 429 (application/json)

        {"error": "Too Many Requests", "message": "Your request was throttled. Please see \"Rate Limit\" section of documentation at http://developers.autopilothq.com."}

+ Response 500 (application/json)

        {"error": "Internal Server Error", "message": "(various)"}


# Group REST Hook Events

### Contact added (Event key: contact_added)

Any time a contact is added to your Autopilot account, this event fires.

Contacts can be added to Autopilot via a variety of methods:

* Manually added
* Spreadsheet import
* Salesforce sync
* API Call (including your own)
* Zapier event
* Segment.com event

***Rate***

It is possible that there will be 10s of 1000s of contact_added events which happen in a small space of time, this would happen in the case of a spreadsheet import or a Salesforce sync. You need to make sure that your system is capable of handling these volumes.

***Retries***

If your REST Hook URL is unavailable, returns an error code (anything other than 200 OK), the Autopilot API will retry up to 3 times to get the request through. After this, the request will be lost.

```
{
  "event": "contact_added",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact updated (Event key: contact_updated)

Any time a contact is updated in Autopilot, this event fires.

Contacts can be updated in Autopilot for a variety of reasons:

* Manually edited
* Spreadsheet import which includes new information
* Salesforce sync which includes new information
* API Call which adds details to contacts
* Contact unsubscribes
* Zapier event
* Segment.com event
* Other Autopilot events which update contact information

***Rate***

It is possible that there will be 10s of 1000s of contact_updated events which happen in a small space of time, this would happen in the case of a spreadsheet import or a Salesforce sync. You need to make sure that your system is capable of handling these volumes.

***Retries***

If your REST Hook URL is unavailable, returns an error code (anything other than 200 OK), the Autopilot API will retry up to 3 times to get the request through. After this, the request will be lost.

```
{
  "event": "contact_updated",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact unsubscribed (Event key: contact_unsubscribed)

This event is triggered when a contact unsubscribes from emails in Autopilot.

The main ways this event could be triggered are:

* The contact is manually unsubscribed by unchecking the box in the contact profile
* A Salesforce sync causes the unsubscribe field to be updated
* A field update on a journey causes the contact to be unsubscribed
* The contact clicks an unsubscribe link in an email you send.

```
{
  "event": "contact_unsubscribed",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact Added To List (Event key: contact_added_to_list)

This event is triggered when a contact is added to a list.

The main ways this event could be triggered are:

* The contact is manually added to the list using the contacts section of the Autopilot UI
* A journey has a step which adds contacts to a list and the contact reaches it
* An API call adds the contact to a list
* Contacts are imported to the list

```
{
  "event": "contact_added_to_list",
  "list_id": "contactlist_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact Removed From list (Event key: contact_removed_from_list)

This event is triggered when a contact is removed from a list.

Note that the `contact_removed_from_list` event will not be triggered if the list itself is deleted. Likewise, if the contact is deleted this event will not be triggered.

The main ways this event could be triggered are:

* The contact is manually removed from the list using the contacts section of the Autopilot UI
* A journey has a step which removes contacts from a list and the contact reaches it
* An API call removes the contact from a list

```
{
  "event": "contact_removed_from_list",
  "list_id": "contactlist_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact Entered Segment (Event key: contact_entered_segment)

This event will be triggered when a contact "enters" a segment, that is, a change is made to a contact that means it meets the segment criteria.

```
{
  "event": "contact_entered_segment",
  "segment_id": "contactlist_ssegED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```

### Contact Left Segment (Event key: contact_left_segment)

This event will be triggered when a contact "leaves" a segment, that is, a change is made to a contact that means it no longer meets the segment criteria.

```
{
  "event": "contact_left_segment",
  "segment_id": "contactlist_ssegED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact_id": "person_ED75BA78-2405-4564-B24C-F2B8F936C7C6",
  "contact": {
      "MailingPostalCode": "94913",
      "FirstName": "Tom",
      "Title": "CEO",
      "LastName": "Greyson",
      "LinkedIn": "tomgreyson",
      "owner_name": "James McKinsey",
      "MailingState": "CA",
      "Email": "trgreyson@gmail.com",
      "Website": "greysondesigns.com",
      "Fax": "3736162442",
      "NumberOfEmployees": 3000,
      "Company": "Greyson Designs",
      "Phone": "3738482121",
      "unsubscribed": false,
      "MailingCity": "San Rafael",
      "owner_first_name": "James",
      "Status": "Nurture",
      "MailingStreet": "Kendra Way",
      "MailingCountry": "United States",
      "Industry": "Technology",
      "LeadSource": "Trial Signup",
      "MobilePhone": "2345456677",
      "Twitter": "trgreyson",
      "Salutation": "Mr.",
      "custom": {"integer--Smog--Level": 4}
  }
}
```
# Group Accessing raw email data

*Note: this feature was sunset on May 4, 2018. The data is now available via Activity Streams: https://autopilothq.zendesk.com/hc/en-us/sections/115000371191-Activity-Streams*

# Group Working with the API

# Apiary mocking server

Please feel free to take advantage of Apiary's built-in examples and mocking server. Please note though that when using the live API, that you will need to provide the `autopilotapikey` header as described below. Apiary doesn't check that this header is valid at the moment, so you will be able to do all of your test requests without providing the API key header. Just note that when you switch to the live API URL, you will need to provide it.

# Staging / Sandbox

Since the API can only operate on individual Autopilot instances, the best way to get yourself a sandbox to play with, is to register for a 30 day trial on autopilothq.com and use it for your testing by generating an API key. Once you are ready to go live, you can switch to the API key of your primary instance.

# Rate Limits

The Autopilot API currently limits you to 20 API requests per second. This limit was set more as a sanity limit than as a way to actually stop you from interacting with our system at the rate you desire.

For bulk adding of contacts please see the Bulk section above so you can or update 100 contacts at a time.

# Cross-site scripting and using Autopilot API in web browsers

We do not allow you to issue Autopilot API commands using AJAX requests. It would be a security risk for you to do this as it would require exposing your API key to the public who could make changes to your Autopilot account.

If you want to be able to make changes via the API based on browser actions, the correct way to do this would be to send an AJAX request to your own backend, clean and verify the data and then issue the API command from your backend.

# Group Custom Field Data Types

**Integer/Numbers**

Must be whole digits: e.g.

```
"integer--Smog-Level": 4
```

They can also be specified as strings as long as there is nothing other than the number in the field, e.g.

```
"integer--Smog--Level": "Monkey" --- this would cause an error
"integer--Smog--Level": "2567" --- this is fine
"integer--Smog--Level": "$2567" --- this would cause an error
```

Note that passing through null is also acceptable for any kind of field, including numbers. This means the field would be considered "blank".

**Floats/Number with decimal**

Must be a valid number: e.g. "float--Smog--Level": 4.01

They can also be specified as strings as long as there is nothing other than the number in the field, e.g.

```
"integer--Smog--Level": "Monkey" --- this would cause an error
"integer--Smog--Level": "2567.58" --- this is fine
"integer--Smog--Level": "2567" --- this is also fine
```

Note that passing through null is also acceptable for any kind of field, including floats. This means the field would be considered "blank".

**Strings**

It's hard to go wrong with strings: e.g. "string--My--String": "Hello how are you going"

We accept any valid UTF-8 string.

**Dates**

Please see the next section of this document for a full description of dates in Autopilot.

# Group Date format in Autopilot

Autopilot accepts dates in the ISO8601 format. Here is a description of the format for dates as used in Autopilot taken directly from the standard:

The formats are as follows. Exactly the components shown here must be present, with exactly this punctuation. Note that the "T" appears literally in the string, to indicate the beginning of the time element, as specified in ISO 8601.

```
   Complete date:
      YYYY-MM-DD (eg 1997-07-16)
   Complete date plus hours and minutes:
      YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
   Complete date plus hours, minutes and seconds:
      YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
   Complete date plus hours, minutes, seconds and a decimal fraction of a second
      YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)

   Where:

     YYYY = four-digit year
     MM   = two-digit month (01=January, etc.)
     DD   = two-digit day of month (01 through 31)
     hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
     mm   = two digits of minute (00 through 59)
     ss   = two digits of second (00 through 59)
     s    = one or more digits representing a decimal fraction of a second
     TZD  = time zone designator (Z or +hh:mm or -hh:mm)
```

There are two ways of handling time zone offsets:

Times are expressed in UTC (Coordinated Universal Time), with a special UTC designator ("Z").
Times are expressed in local time, together with a time zone offset in hours and minutes. A time zone offset of "+hh:mm" indicates that the date/time uses a local time zone which is "hh" hours and "mm" minutes ahead of UTC. A time zone offset of "-hh:mm" indicates that the date/time uses a local time zone which is "hh" hours and "mm" minutes behind UTC.

Examples of valid dates are:

```
"date--Birthday": "2015-12-01"
"date--Appointment": "2015-10-10T13:50:00Z"
```

We also accept dates in straight-up American format such as:

```
"date--Some--Date":"12/30/2015"
```

Reference:

* [Relevant XKCD cartoon](https://xkcd.com/1179/)
* [Discussion on the correct way to handle dates in APIs](http://apiux.com/2013/03/20/5-laws-api-dates-and-times/)

**Note on Dates returned from the Autopilot API**

While we accept dates in whatever timezone you provide, we *always* return dates in UTC/GMT time. It is up to you to convert those dates to the timezone you need after they are retrieved from Autopilot.
