A documentation of the first version (v0) of the Lavaboom API, focused on typical user interactions with the client.
client
is any Angular, iOS, Android, etc application that uses the Lavaboom APIuser
is an actual person using a Lavaboom appTBP
To Be Planned, i.e. not a v0 feature
POST /emails
Auth: {token}
{
"to": ["example@domain.com","Andrei Simionescu", "andrei@lavaboom.com"],
"cc": ["{some_user_id}"],
"bcc": [],
"reply_to": "{email_id}",
"thread_id": "{thread_id}",
"body": "{email_text}",
"attachment_ids": ["{some_uuid}, {other_uuid}"]
}
token
is the auth token, passed as anAuth
HTTP header.to
,cc
,bcc
are arrays of strings that can be an email address, a full name, or a user ID. They are all optional, for instance ifthread_id
is specified and no new members are introduced to the discussion.email_id
if this is specified we know how this email fits in a current email discussion.thread_id
if this is a reply to an existing thread.email_text
is the content of the email, excluding attachments.attachment_ids
is a list of attachment IDs. Attachment uploading: POST to/upload
, returnsattachment_id
s. If they're not used, uploaded attachments expire in 24h. Also, while will in beta, the upload limit per file will be 25MB. The attachments must be PGP-encrypted, so the user must be warned that changing the list of recipients after uploading an attachment means he will have to re-upload that file.
Response:
success
can bedelivered
orerror
email_id
is the ID of the new email, if the operation was successfulmessage
is usually an error code, if necessary
Issues:
- This can be trickier if we add drafts and autosave functionality, so we'll skip that for v0.
- By adding websockets we can check for successful delivery and notify the user that the email has been delivered.
This means that the API will return
success: "queued"
or similar when POST-ing to/emails
. - If this is an encrypted email (detectable on the server side automatically), the client must have already figured out the public keys and performed encryption.
GET /threads?label=inbox
Auth: {token}
token
is the auth tokenoffset
andlimit
, not specified, handle pagination and are by default 0 and 50.label
can be a label name or a label ID. Querying using a ID is faster.
Response:
{
"n_threads": {number_of_threads},
"threads": [
{
"thread_id": "{thread_id}",
"participants": "{participants_snippet}",
"subject": "{subject}",
"snippet": "{snippet}",
"labels": ["inbox","{some_label}"],
"n_emails": {n_emails},
"has_attachments": {has_attachments},
"is_starred": {is_starred},
"encription_level": "{encryption_level}",
"avatar": "{avatar_id}",
"is_postponed": {is_postponed}
},
[...]
]
}
number_of_threads
is an integer representing the number of threads found.thead_id
is provided because more data about the thread can be extracted by querying explicitly.participants_snippet
is a string that indicates to the user who the last interaction happened with. Example: "Billy Joel", "To: John Smith, Billy Joel, and 256 others", etc.subject
is the subject of the latest email in the thread.snippet
is a snippet of the latest email in the thread.some_label
is a label name. It would be pointless to return UUIDs here.n_emails
is the number of emails in this thread. No need to report the number of unread emails separately.has_attachments
is a bool value indicating whether the last email has any attachments. (Or the whole thread? This is not decided yet.)is_starred
is a bool value indicating whether this thread has been starred.encryption_level
can be a couple of string values (unencrypted, strong, weak, medium, and danger) and depends on how many emails in the thread are encrypted and on the quality of the public keys used for encryption.avatar_id
will be an id for an avatar (of the person last interacted with in this thread). TBP.is_postponed
will be useful when we implement Mailbox-like productivity features.
Issues:
- Add websockets to push new emails to the client without an explicit query.
API v0 will only feature simple keyword search. The smart and fuzzy bits will happen server side.
GET /threads?q=my+search+query
Auth: {token}
You can combine label and keyword search.
GET /threads?label=inbox&q=where+my+email+at
Auth: {token}
The data can be sent via JSON too, although I think the URL way is more common for GET requests. The response is identical to the previous action.
GET /threads?label={label}
Auth: {token}
Response: See "Checking the inbox"
GET /me/settings
Auth: {token}
PUT /me/settings
Auth: {token}
{
"{key}": "{value}"
}
Pretty self explanatory. [check out possible values here or similar]
Typical actions on emails that the user performs in their inbox:
- archive
- reply
- report spam
- mark unread
- (TBP) postpone/reschedule email
- (TBP) mute thread
- delete
- move
Issues:
- A simple mechanism for batching requests needs to be introduced to handle such tasks. Usually multiple emails are handled at once (archive, postpone, etc).
POST /contacts
Auth: {token}
{
"name": "John Smith",
"email": {
"address": "example@domain.com",
"public_key": "{pgp_key}",
"fingerprint": "{fingerprint}"
}
"fields": {
"first_name": "John",
"family_name": "Smith",
"iphone": "0044123456789",
"{key}": "{value}"
}
}
token
is the authentication tokenpgp_key
is the full PGP key for this email address. Any eventual ambiguity will be solved client-side.fingerprint
can be submitted together with the key, for added security. If only the fingerprint is submitted, the server will try to match it with a key on the Lavaboom key server, or if that fails, on a public key server.
Response:
{
"success": "{success}",
"message": "{message}"
}
success
is a boolean. (Should it be a string?)message
explains what happened in case of an error. For example, an email address could've already been in the contacts' list.
GET /contacts/?q=john+smith
Auth: {token}
Response: similar to what's submitted when adding a contact.
DELETE /contacts/{id}
Auth: {token}
Response: success
and message
PUT /contacts/{id}
Auth: {token}
{
"{key}": "{value}"
}
The user interaction with the Contacts screen is pretty straightforward, the only interesting aspect is added by the fact that we need to manage public keys too. There are a number of ways to approach this, we must (as always) try to balance the utmost security with convenience.
The options are:
- completely manual key management; additionally we might let user sync with reputable key servers
- completely managed key management; the Lavaboom key server is considered the ultimate authority on public key authenticity
- flexible managed scheme; vote-based system – Lavaboom's key server can have multiple user-sourced public keys per email address, and the users can vote on their authenticity, and elect which key to use (or to upload their own)
I personally prefer the last option, eventually augmented by using the existing public key servers to populate our key server with the keys corresponding to the email addresses used by our users (obviously, in a batched, unobvious way, to protect our users' privacy).
POST /signup
{
"username": "{user}",
"password": "{pass}",
"reg_token": "{reg}"
}
user
is the desired username, {a-zA-Z0-9_.}, length between 2 and 32 characters. Like Gmail, the actual username doesn't contain periods, but the user has one preferred style (e.g.john.smith
), and can use any variation of his username with periods, as long as they're not subsequent characters or at the beginning or the end of the username.pass
is the user's password, hashed with SHA-512.
Response:
{
"success": {success},
"message": "{message}",
"position": {position}
}
success
is a boolean indicating whether the operation was successful.message
is submitted to indicate an error, e.g. "Username already exists".position
is submitted if the operation was successful, but a reg_token wasn't submitted, and represents the user's position in the queue of people waiting for access to Lavaboom.
POST /login
{
"username": "{user}",
"password": {pass}
}
success
is a boolean.password
is the submitted password, hashed with SHA-512.
Response:
{
"success": "{success}",
"message": "{message}",
"token": "{token}",
"exp_date": "{exp_date}"
}
success
is a boolean.message
is an error message.token
is a UUID that acts as a session token.exp_date
is the date when the session token expires. This will be set pretty aggressively, due to the nature of our product.
Issues:
- If the user is on mobile, the
exp_date
will be set much more permissively. A mobile login will be detected via HTTP headers.
DELETE /logout
Auth: {token}
Response:
{
"success": "{success}",
"message": "{message}"
}