API for your own code.
Read the mail in a workspace, add internal notes, assign and close conversations. One key, one header, JSON in and out. Version v1; a change that would break your code arrives as a new version, not as a surprise.
Keys
A workspace owner makes keys under Settings, API keys. A key has a name, an expiry date and one of two levels: read only, or read and change. You can have several, so a script that only reports never needs the right to close anything.
The key is shown once, when it is created. We keep only a hash of it, so a copy of our database is not a set of working keys. Lost one? Revoke it and make another.
Send it on every request:
curl https://coffer.email/api/v1/me \ -H "Authorization: Bearer cof_your_key_here"
Base address: https://coffer.email/api/v1
Endpoints
GET/api/v1/meRead only
Check the key and see which workspace it opens
The first call to make. Confirms the key works, names the workspace and says what the key may do. Also tells you whether the workspace is read only because it is scheduled for deletion.
Returns
workspace(id, name, readOnly) andtoken(name, scope).GET/api/v1/mailboxesRead only
Mailboxes connected to the workspace
Every mailbox with the id you need for the
mailboxfilter on conversations.Returns
data: id, address, name, receiveMode, sendMode, status, color.GET/api/v1/tagsRead only
Tags used in the workspace
The
slugis what thetagfilter on conversations expects.Returns
data: id, name, slug, color.GET/api/v1/membersRead only
People in the workspace
Ids from here are what
assignand the author of a note expect. Names repeat and change; ids do not.Returns
data: id, name, email, role.GET/api/v1/contactsRead only
Customers who have written in
Contacts hidden in the panel are left out, exactly as they are in the customer list.
- qquery
- string Part of an address, a name or a company.
- limitquery
- integer 1 to 200, 50 by default.
Returns
data: id, email, name, company, phone, note, conversationCount, createdAt.GET/api/v1/conversationsRead only
List conversations, newest message first
Paging uses a cursor, not page numbers: mail keeps arriving, so page two would show you the same rows again. Take
nextBeforefrom the response and send it back asbefore. WhennextBeforeis null, you have everything.- statusquery
- open | closed Only open or only closed conversations.
- mailboxquery
- string Mailbox id from /mailboxes.
- tagquery
- string Tag slug from /tags.
- assigneequery
- string Member id from /members.
- qquery
- string Text in the subject, the preview or the contact.
- spamquery
- boolean
truereturns spam instead of the normal list. - limitquery
- integer 1 to 100, 25 by default.
- beforequery
- ISO 8601
nextBeforefrom the previous page.
Returns
data: conversations with mailbox, contact, assignee and tags.nextBefore: cursor or null.GET/api/v1/conversations/{id}Read only
One conversation with its whole thread
Messages in the order they arrived, plus internal notes with their replies. A message with
draft: truewas written in the panel and never sent. An id from another workspace answers 404, not 403.- idpath, required
- string Conversation id.
Returns The conversation, plus
messagesandnotes.POST/api/v1/conversations/{id}/notesRead and change
Add an internal note
Notes are what the team says to each other beside the thread; the customer never sees them.
authorIdis required, because a note is a sentence from a person and a key is not a person.- idpath, required
- string Conversation id.
- bodybody, required
- string The note, up to 5000 characters.
- authorIdbody, required
- string Member id from /members.
- mentionIdsbody
- string[] Member ids to point at. They see the conversation under Mentioning me.
Returns The created note: id, body, createdAt, mentionIds. Status 201.
POST/api/v1/conversations/{id}/assignRead and change
Give a conversation to someone, or take it off them
Send
memberId: nullto unassign. The history line says a program did it, not a person - we do not invent a click that never happened.- idpath, required
- string Conversation id.
- memberIdbody, required
- string | null Member id from /members, or null to unassign.
Returns
idand the newassigneeId.POST/api/v1/conversations/{id}/statusRead and change
Close a conversation or open it again
Closing always says how it ended - a closed conversation without an outcome is a statistic nobody can use.
- idpath, required
- string Conversation id.
- statusbody, required
- open | closed What it becomes.
- outcomebody
- resolved | not_resolved Required when closing, ignored when opening.
Returns
id,statusandoutcome.
Errors
Every failure has the same shape, so you write the handling once. code is for your program and never changes; message is for whoever reads the log and may be reworded.
{ "error": { "code": "unauthorized", "message": "Missing or invalid API token…" } }- 401unauthorizedNo key, a key that never existed, one that expired or was revoked.
- 403forbiddenA read-only key tried to change something.
- 403read_onlyThe workspace is scheduled for deletion, so nothing can change.
- 404not_foundNo such conversation in this workspace.
- 400invalid_requestA parameter is missing or has a shape we cannot use.
Something missing? Write to [email protected] and say what you are building - an endpoint we have not written yet is easier to add before someone works around its absence.