REST API

Introduction

Enchant is a fully hosted omnichannel shared inbox solution. We provide a REST API built on pragmatic RESTful design principles.

Our API uses resource-oriented URLs that leverage built in features of HTTP, like authentication, verbs and response codes. All request and response bodies are JSON encoded, including error responses. Any off-the-shelf HTTP client can be used to communicate with the API.

We believe an API is a user interface for a developer - accordingly, we've made sure our API can be easily explored from the browser!

Changes

This is a versionless API. Advance notification of breaking changes will be available in this document and will be sent by email to our developer mailing list.

Sign up for the Enchant Developer mailing list

Authentication

Requests to the API are authenticated using access tokens.

To get an access token, install the API app from the apps tab of your help desk settings. Each instance of the API app has it's own access token.

Once you have an access token, it can be provided to the API as a bearer token:

 curl -H 'Authorization: Bearer token' https://site.enchant.com/api/v1/tickets

Note: An API access token gives the holder unrestricted access to your account data. It should be guarded like a password.

Requests

The base URL of the API is https://site.enchant.com/api/v1 where site should be replaced with your help desk identifier.

HTTPS

All requests to the API must be sent over HTTPS. Any requests over plain HTTP will fail.

JSON Bodies

All POST, PUT, PATCH requests are JSON encoded and must have content type of application/json, or the API will return a 415 Unsupported Media Type status code.

$ curl https://site.enchant.com/api/v1/users/543abc \
    -X PATCH \
    -H 'Content-Type: application/json' \
    -d '{"first_name":"John"}'

HTTP Verbs

We use standard HTTP verbs to indicate intent of a request:

  • GET - To retrieve a resource or a collection of resources
  • POST - To create a resource
  • PATCH - To modify a resource
  • PUT - To set a resource
  • DELETE - To delete a resource

Limited HTTP Clients

If you are using an HTTP client that doesn't support PUT, PATCH or DELETE requests, send a POST request with an X-HTTP-Method-Override header specifying the desired verb.

$ curl https://site.enchant.com/api/v1/users/543abc \
    -X POST \
    -H "X-HTTP-Method-Override: DELETE"

If you are using an HTTP client that doesn't support sending the "Bearer" scheme as part of the Authorization header, the access token can also be provided over Basic Auth with a dummy password:

$ curl -u token:X https://site.enchant.com/api/v1/tickets

Responses

All response bodies are JSON encoded.

A single resource is represented as a JSON object:

{
  "field1": "value",
  "field2": true,
  "field3": []
}

A collection of resources is represented as a JSON array of objects:

[
  {
    "field1": "value",
    "field2": true,
    "field3": []
  },
  {
    "field1": "another value",
    "field2": false,
    "field3": []
  }
]

Timestamps are in UTC and formatted as ISO8601.

Unset fields will be represented as a null instead of not being present. If the field is an array, it will be represented as an empty array - ie [].

HTTP Status Codes

We use HTTP status codes to indicate success or failure of a request.

Success codes:

  • 200 OK - Request succeeded. Response included
  • 201 Created - Resource created. URL to new resource in Location header
  • 204 No Content - Request succeeded, but no response body

Error codes:

  • 400 Bad Request - Could not parse request
  • 401 Unauthorized - No authentication credentials provided or authentication failed
  • 403 Forbidden - Authenticated user does not have access
  • 404 Not Found - Resource not found
  • 415 Unsupported Media Type - POST/PUT/PATCH request occurred without a application/json content type
  • 422 Unprocessable Entry - A request to modify or create a resource failed due to a validation error
  • 429 Too Many Requests - Request rejected due to rate limiting
  • 500, 501, 502, 503, etc - An internal server error occured

Errors

All 400 series errors (400, 401, 403, etc) will be returned with a JSON object in the body and a application/json content type.

{
   "message": "Not Found"
}

500 series error codes (500, 501, 502, etc) do not return JSON bodies.

Validation Errors

In case of validation errors on a POST/PUT/PATCH request, a 422 Unprocessable Entry status code will be returned. The JSON response body will include an array of error messages.

{
  "message": "Validation Failed",
  "errors": [
    {
      "message": "Field is not valid"
    },
    {
      "message": "OtherField is already used"
    }
  ]
}

Rate Limiting

The API is rate limited to 100 credits per minute for an entire account, across all end points, users and tokens. A request is typically worth 1 credit. However, embedding and counting can increase the the amount of required credits for a request. All responses include headers describing the current rate limit status:

Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
  • Rate-Limit-Limit - Total credit for current period
  • Rate-Limit-Remaining - Remaining credit for current period
  • Rate-Limit-Used - Number of credits used for this request
  • Rate-Limit-Reset - Number of seconds until the the credit count resets

If the rate limit is hit, the API will return a 429 Too Many Requests status code. In this situation, your application should not send any further requests until Rate-Limit-Reset seconds have elapsed.

Burst Limiting: In addition to the rate limits described above, the API has a secondary burst limiter of 6 requests per second for an entire account.

Field Filtering

All responses from the API can limit fields to only the fields you need. Just pass in a fields query parameter with a comma separated list of fields you need

For example:

GET /api/v1/users?fields=id,first_name

Would have the following response body:

[
  {
    "id": "543abc",
    "first_name:": "John"
  },
  {
    "id": "543add",
    "first_name:": "Bob"
  }
]

Embedding

Many endpoints support embedding related resources to minimize the number of required API round trips.

Embedding is triggered by passing in an embed query parameter, which takes a comma separated list of endpoint types.

GET /api/v1/tickets/543abc?embed=labels
{
  "id": "543add",
  "type": "email",
  "label_ids": [ "123abc", "234bcd" ],
  "labels": [
    {
      "id": "123abc",
      "name": "Refund"
    },
    {
      "id": "234bcd",
      "name": "VIP"
    }
  ],
  ... other ticket fields ...
}

Only certain resource types can be embedded from certain endpoints. The endpoint documentation specifies which ones can be embedded.

Each embedded type uses an additional rate limit credit.

Counting

All endpoints that return a collection can provide a count of the total number of results. To request a count, just include a count=true as a query parameter. The count will be returned in a header Total-Count.

GET /api/v1/tickets?count=true
200 OK
Total-Count: 135
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 98
Rate-Limit-Used: 2
Rate-Limit-Reset: 20
Content-Type: application/json
[
  ... results ... 
]

Note that the count represents the total amount of available results, not the amount returned as part of the current response.

Counting uses an additional rate limit credit.

Enveloping

If your HTTP client makes it difficult to read status codes or headers, we can package everything neatly into the response body. Just include envelope=true as a request parameter and the API will always return a 200 HTTP status code. The real status, headers and response will be within the body.

GET /api/v1/users/does-not-exist?envelope=true
200 OK
{
  "status": 404,
  "headers": {
    "Rate-Limit-Limit": 100,
    "Rate-Limit-Remaining": 50,
    "Rate-Limit-Used": 0,
    "Rate-Limit-Reset": 25
  },
  "response": {
    "message": "Not Found"
  }
}

Pagination

Requests for collections can return between 0 and 100 results, controlled using the per_page and page query parameters. All end points are limited to 10 results by default.

GET /api/v1/tickets?per_page=15&page=2

Not all endpoints support pagination. If they do, it will be mentioned in their documentation.

Sorting

Some endpoints offer result sorting, triggered using the sort query parameter. The value of sort is a comma separated list of fields to sort by. You can specify descending sort by prepending - to a field. Not all fields can be sorted on. The endpoint documentation will list supported sort options.

The default sort for all endpoints is descending order of creation.

To get recently updated tickets, sorted in descending order of updated_at:

GET /api/v1/tickets?sort=-updated_at

Tickets

A ticket contains one or more messages, representing a conversation with a customer.

FieldTypeNotes
idstring
numberintegerFriendly ticket number, unique across the help desk.
customer_idstringAssociated customer.
user_idstringAssigned user. Can be null.
inbox_idstringAssociated inbox. A ticket always belongs to an inbox.
label_idsarray of strings
statestringOne of: open, hold, closed, snoozed, archived
snoozed_untiltimestamp
subjectstring
typestringOne of: email, twitter, twitter_dm, phone, chat, web, sms, whatsapp, fb_messenger, instagram_dm, call
spamboolean
trashboolean
updated_attimestamp
created_attimestamp
reply_tostringDEPRECATED. Default To: field of a new reply.
reply_ccstringDEPRECATED. Default Cc: field of a new reply.

Listing tickets

GET /api/v1/tickets
Query ParameterNotes
idComma separated list of ticket ids
inbox_idComma separated list of inbox ids
stateComma separated list of states: open, hold, closed
user_idComma separated list of user ids
label_idComma separated list of label ids
typeComma separated list of ticket types
spamOne of: true,false
trashOne of: true,false
since_created_atAny tickets created since specified time (should be in UTC and ISO8601 formatted)
eg: 2023-08-02T13:41:10Z
since_updated_atAny tickets updated since specified time (should be in UTC and ISO8601 formatted)
eg: 2023-08-02T13:41:10Z
pagePage number, starting from 1.
Note: When retrieving more than 10000 total tickets, iterate using since_created_at instead of page.
per_pageAny integer between 0 and 100, inclusive
sortOne of: updated_at, -updated_at, created_at, -created_at, user_id,-updated_at
fieldsSee Field Filtering
countSee Counting
envelopeSee Enveloping

Getting unassigned tickets:

GET /api/v1/tickets?user_id=null&sort=-updated_at&count=true&per_page=1
200 OK
Total-Count: 23
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 98
Rate-Limit-Used: 2
Rate-Limit-Reset: 20
Content-Type: application/json
[
  {
    "id": "51e6e9",
    "number": 2209,
    "user_id": "501efc",
    "state": "closed",
    "subject": "help, it didn't work!",
    "labels_ids": [
      "41e3dc"
    ],
    "customer_id": "51b3e9",
    "type": "email",
    "inbox_id": "51e3f9",
    "spam": false,
    "trash": false,
    "updated_at": "2023-07-25T12:19:33Z",
    "created_at": "2023-07-17T18:58:44Z",
    "summary": "I was trying to do something and it just didn't work.  Can you help?"
  }
]

Getting a single ticket

GET /api/v1/tickets/ticket_id
Query ParameterNotes
embedComma separated list of embeddables: user, inbox, customer, labels, messages
DEPRECATED options: group
fieldsSee Field Filtering
envelopeSee Enveloping

Sample Request:

GET /api/v1/tickets/51e6e9&embed=customer
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 96
Rate-Limit-Used: 2
Rate-Limit-Reset: 18
Content-Type: application/json
{
  "id": "51e6e9",
  "number": 2209,
  "user_id": "501efc",
  "state": "closed",
  "subject": "help, it didn't work!",
  "label_ids": [
    "41e3dc"
  ],
  "customer_id": "51b3e9",
  "customer": {
    "id": "51b3e9",
    "first_name": "Michael",
    "last_name": "Smith",
    "summary": null,
    "contacts": [
      {
        "id": "5149d9",
        "type": "email",
        "value": "michael.smith@example.com",
      }
    ]
  },
  "type": "email",
  "inbox_id": "51e3f9",
  "spam": false,
  "trash": false,
  "updated_at": "2023-07-25T12:19:33Z",
  "created_at": "2023-07-17T18:58:44Z",
  "summary": "I was trying to do something and it just didn't work.  Can you help?"
}

Updating a ticket

PATCH /api/v1/tickets/ticket_id
FieldNotes
user_id
inbox_id
stateOne of: open, hold, closed
label_idsArray of label id strings to set the ticket to. An Empty array will remove all labels from the ticket.
spamOne of: true, false. spam and trash cannot both be true at the same time.
trashOne of: true, false. spam and trash cannot both be true at the same time.
subject

Closing a ticket:

PATCH /api/v1/tickets/51b3e9
Content-Type: application/json
{
  "state": "closed"
}

Assigning to a specific user:

PATCH /api/v1/tickets/51b3e9
Content-Type: application/json
{
  "user_id": "555acc"
}

Sending to trash:

PATCH /api/v1/tickets/51b3e9
Content-Type: application/json
{
  "trash": true
}

Setting labels:

PATCH /api/v1/tickets/51b3e9
Content-Type: application/json
{
  "label_ids": [
    "41e3dc",
    "423ccc"
  ]
}

Adding or removing labels

An additional endpoint is available to add or remove labels without impacting existing labels on the ticket.

Adding a label:

PUT /api/v1/tickets/ticket_id/labels/label_id
Content-Type: application/json

Adding multiple labels:

PUT /api/v1/tickets/ticket_id/labels/label_id1,label_id2
Content-Type: application/json

Removing a label:

DELETE /api/v1/tickets/ticket_id/labels/label_id

Removing multiple labels:

DELETE /api/v1/tickets/ticket_id/labels/label_id1,label_id2

Creating a new ticket

POST /api/v1/tickets
FieldRequiredNotes
typeyesMust be set to email. Tickets of other types cannot be created from the public API.
subjectyesSubject of the ticket
customer_idyesAssociated customer.
customernoCustomer object that can be provided instead of customer_id. Will be used to lookup customer_id.
If no matching customer found, one will be created based on the provided details.
user_idno
inbox_idno
messagesnoArray of message objects to be created alongside ticket.
reply_toDEPRECATED. Default To: address for replies
reply_ccDEPRECATED. Default Cc: address for replies

Creating a ticket for a contact form:

POST /api/v1/tickets
Content-Type: application/json
{
  "customer": {
    "first_name": "John",
    "last_name": "Smith",
    "contacts": [
      {
        "type": "email",
        "value": "john@example.com"
      }
    ]
  },
  "messages": [
    {
      "type": "note",
      "user_id": "6130e332",
      "body": "IP address: 1.2.3.4, Page: https://site.com/page"
    },{
      "type": "reply",
      "direction": "in",
      "from_name": "John Smith",
      "from": "john@example.com",
      "body": "My package didn't arrive. Help!"
    }
  ],
  "type": "email",
  "user_id": "522aaa",
  "inbox_id": "533bcd",
  "subject": "Where's my package?"
}
201 Created
Location: https://site.enchant.com/api/v1/tickets/51f6e9
Content-Type: application/json
{
  "id": "51f6e9",
  "number": 2210,
  "user_id": "522aaa",
  "state": "open",
  "subject": "Where's my package?",
  "label_ids": [
  ],
  "customer_id": "4332ca",
  "type": "email",
  "inbox_id": "533bcd",
  "spam": false,
  "trash": false,
  "updated_at": "2023-07-17T18:58:44Z",
  "created_at": "2023-07-17T18:58:44Z",
  "summary": null
}

Messages

Replies and notes are all represented as messages on a ticket.

FieldTypeNotes
idstring
from_namestringdisplay name associated with message
bodystring
htmlizedbooleantrue if the body is html
attachmentsarray of attachments
user_idstringid of user who created the message. null if a customer
typestringOne of: reply or note
created_attimestamp

Additional fields for messages of type reply:

FieldTypeNotes
directionstringone of:
in - an inbound message from a customer
out - an outbound message to a customer
fromstringrepresents contact information of sender
tostringrepresents contact information of recipient
more_bodystringcontains signature if removed from body.

Listing messages

Messages can be retrieved as embedded resources on a ticket.

GET /api/v1/tickets/ticket_id?embed=messages

Sample Request:

GET /api/v1/tickets/513e9c?embed=messages
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 98
Rate-Limit-Used: 2
Rate-Limit-Reset: 20
Content-Type: application/json
{
  "id": "513e9c",
  "number": 224,
  "messages": [
    {
      "id": "51f613",
      "type": "reply",
      "direction": "in",
      "from_name": "Chris Johnson",
      "body": "<p>I was trying to do something and it just didn't work.</p><p>Can you help?</p>",
      "htmlized": true,
      "from": "Chris Johnson <chris@example.com>",
      "to": "support@example.com",
      "user_id": null,
      "attachments": [
      ],
      "created_at": "2023-07-29T07:03:10Z"
    },
    {
      "id": "51f677",
      "type": "reply",
      "direction": "out",
      "from_name": "Mary",
      "body": "Hi Chris,<br><br>Ofcourse I can help!<br><br>Cheers,<br>Mary",
      "htmlized": true,
      "from": null,
      "to": "chris@example.com",
      "user_id": "501efc",
      "attachments": [
      ],
      "created_at": "2023-07-29T14:10:58Z"
    }
  ],
  "user_id": "501efc",
  "state": "closed",
  "subject": "i need some help",
  "label_ids": [
  ],
  "customer_id": "51f613",
  "type": "email",
  "inbox_id": "513210",
  "updated_at": "2023-07-29T14:10:59Z",
  "created_at": "2023-07-29T07:03:10Z",
  "spam": false,
  "trash": false,
  "summary": "I was trying to do something and it just didn't work. Can you help?"
}

Creating a new note

POST /api/v1/tickets/ticket_id/messages
FieldTypeRequiredNotes
typestringyesMust be set to: note
user_idstringyesid of user to associate with the message.
bodystringyes
htmlizedbooleanyestrue if the body is html
attachment_idsarray of stringsnoSee attachments

Creating a new inbound reply

POST /api/v1/tickets/ticket_id/messages
FieldTypeRequiredNotes
from_namestringyes
typestringyesMust be set to: reply
directionstringyesMust be set to: in
bodystringyes
htmlizedbooleanyestrue if the body is html
fromstringyes
tostringno
attachment_idsarray of stringsnoSee attachments

Sample request:

POST /api/v1/tickets/513ecc/messages
Content-Type: application/json
{
  "direction": "in",
  "type": "reply",
  "from": "chris@example.com",
  "body": "Thank you for your help!"
}

Creating a new outbound reply

POST /api/v1/tickets/ticket_id/messages
FieldTypeRequiredNotes
typestringyesMust be set to: reply
directionstringyesMust be set to: out
bodystringyes
htmlizedbooleanyestrue if the body is html
user_idstringyesid of user to associate with the message.
tostringyes
attachment_idsarray of stringsnoSee attachments

Sample request:

POST /api/v1/tickets/513ecc/messages
Content-Type: application/json
{
  "direction": "out",
  "type": "reply",
  "to": "chris@example.com",
  "body": "Hi Chris, I can help! Here's what you need to do ...",
  "user_id": "501efc"
}

Attachments

An attachment is uploaded to the system first. Then the attachment id is provided when creating a message. An attachment can only be associated with one message. Any unassociated attachments will be deleted.

FieldTypeNotes
idstring
namestringfile name
sizeintegersize in bytes
typestringmime type

Getting an attachment

GET /api/v1/attachments/attachment_id

Sample Request:

GET /api/v1/attachments/54318c
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
Content-Type: application/json
{
  "id": "54318c",
  "name": "MyFile.zip",
  "size": 134345,
  "type": "application/zip"
}

Creating an attachment

POST /api/v1/attachments
FieldTypeRequiredNotes
namestringyesfile name
typestringyesmime type
datastringyesBase64 encoded file data

Sample attachment, including message creation:

POST /api/v1/attachments
Content-Type: application/json
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
{
  "name": "MyFile.zip",
  "type": "application/zip",
  "data": "UEsDBAoAAAAAAFmu/kLPx4wKGwAAABsAAAAKABwAcmVhZG1lLnR4dFVUCQAD
           OjX4UTo1+FF1eAsAAQToAwAABOgDAABNYXkgdGhlIGZvcmNlIGJlIHdpdGgg
           eW91LgpQSwECHgMKAAAAAABZrv5Cz8eMChsAAAAbAAAACgAYAAAAAAABAAAA
           tIEAAAAAcmVhZG1lLnR4dFVUBQADOjX4UXV4CwABBOgDAAAE6AMAAFBLBQYA
           AAAAAQABAFAAAABfAAAAAAA="
}
201 Created
Location: https://site.enchant.com/api/v1/attachments/5338df
Content-Type: application/json
{
  "id": "5338df",
  "name": "MyFile.zip",
  "type": "application/zip",
  "size": 197
}

Now, a message needs to be created using the attachment:

POST /api/v1/tickets/513ecc/messages
Content-Type: application/json
{
  "type": "note",
  "body": "Attaching the file!",
  "htmlized": false,
  "user_id": "501efc",
  "attachment_ids": [
    "5338df"
  ]
}

Users

FieldTypeNotes
idstring
first_namestring
last_namestring
emailstring

Listing users

GET /api/v1/users

Sample Request:

GET /api/v1/users
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
Content-Type: application/json
[
  {
    "id": "501efc",
    "first_name": "John",
    "last_name": "Smith",
    "email": "john@example.com"
  },
  {
    "id": "501edd",
    "first_name": "Michael",
    "last_name": "Jones",
    "email": "michael@example.com"
  }
]

Customers

FieldTypeNotes
idstring
first_namestring
last_namestring
summarystring
contactsarray of contacts

Listing customers

GET /api/v1/customers
Query ParameterNotes
contacts.typeOne of: email, twitter, phone
contacts.valueEmail address or twitter screen name
pagePage number, starting from 1
Note: When retrieving more than 10000 total customers, iterate using since_created_at instead of page.
per_pageAny integer between 0 and 100, inclusive
fieldsSee Field Filtering
countSee Counting
envelopeSee Enveloping
since_created_atAny customers created since specified time (should be in UTC and ISO8601 formatted)
eg: 2023-08-02T13:41:10Z
sortOne of: created_at

Sample Request:

GET /api/v1/customers
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
Content-Type: application/json
[
  {
    "id": "51f846",
    "first_name": "Ruby",
    "last_name": "Miller",
    "summary": null,
    "contacts": [
      {
        "id": "51f8aa",
        "type": "email",
        "value": "ruby@example.com"
      }
    ]
  },
  {
    "id": "51f7a7",
    "first_name": "Maggie",
    "last_name": "Miller",
    "summary": null,
    "contacts": [
      {
        "id": "51f7a9",
        "type": "email",
        "value": "maggie@example.com"
      }
    ]
  }
]

Find a customer by email address

GET /api/v1/customers?contacts.type=email&contacts.value=email_address

Sample Request:

GET /api/v1/customers?contacts.type=email&contacts.value=john@example.com
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
Content-Type: application/json
[
  {
    "id": "51f232",
    "first_name": "John",
    "last_name": "Smith",
    "summary": null,
    "contacts": [
      {
        "id": "51f352",
        "type": "email",
        "value": "john@example.com"
      }
    ]
  }
]

Get a single customer

GET /api/v1/customers/customer_id

Sample Request:

GET /api/v1/customers/51f7a7
200 OK
Rate-Limit-Limit: 100
Rate-Limit-Remaining: 99
Rate-Limit-Used: 1
Rate-Limit-Reset: 20
Content-Type: application/json
{
  "id": "51f7a7",
  "first_name": "Maggie",
  "last_name": "Miller",
  "summary": null,
  "contacts": [
    {
      "id": "51f7a9",
      "type": "email",
      "value": "maggie@example.com"
    }
  ]
}

Updating a customer

PATCH /api/v1/customers/customer_id
FieldRequiredNotes
first_nameno
last_nameno
summaryno
contactsnoArray of type & value pairs. Type must be one of email, twitter, phone.

Updating a customer's name:

PATCH /api/v1/customers/51f7a7
Content-Type: application/json
{
  "first_name": "Maggy",
  "last_name": "Miller"
}

Updating contacts of a customer:

PATCH /api/v1/customers/51f7a7
Content-Type: application/json
{
  "contacts": [
    {
      "type": "email",
      "value": "maggy@example.com"
    }
  ]
}

Adding custom summary info:

PATCH /api/v1/customers/51f7a7
Content-Type: application/json
{
  "summary": "VIP customer"
}

Creating a new customer

POST /api/v1/customers
FieldRequiredNotes
first_nameno
last_nameno
summaryno
contactsnoArray of type & value pairs. Type must be one of email, twitter, phone.

Sample Request:

POST /api/v1/customers
Content-Type: application/json
{
  "first_name": "John",
  "last_name": "Smith",
  "contacts": [
    {
      "type": "email",
      "value": "john@example.com"
    }
  ]
}
201 Created
Location: https://site.enchant.com/api/v1/customers/51c3d1
Content-Type: application/json
{
  "id": "51c3d1",
  "first_name": "John",
  "last_name": "Smith",
  "summary": null,
  "contacts": [
    {
      "id": "5e1243",
      "type": "email",
      "value": "john@example.com"
    }
  ]
}

Contacts

A contact represents a unique identifier (eg: email address, phone number) for the customer. Contacts are automatically loaded with customer records.

FieldTypeNotes
idstring
typestringOne of: email, twitter, phone
valuestring

Creating a contact

POST /api/v1/customers/customer_id/contacts
FieldRequiredNotes
typeyesOne of: email, twitter, phone
valueyes

Sample Request:

POST /api/v1/customers/51f846
Content-Type: application/json
{
  "type": "email",
  "value": "john@example.com"
}
201 Created
Location: https://site.enchant.com/api/v1/customers/514846/contacts/5197cc
Content-Type: application/json
{
  "id": "5197cc",
  "type": "email",
  "value": "john@example.com"
}

Deleting a contact

DELETE /api/v1/customers/customer_id/contacts/contact_id