-
Notifications
You must be signed in to change notification settings - Fork 1
API Protocol
GET /v1/accounts/{transport}/code/{number}
The client requests an SMS or Voice verification code for the client's PSTN number.
-
transportis the stringsmsorvoice, depending on how the client would like a verification code delivered. -
numberis the client's PSTN number.
Returns:
-
200request was processed successfully. -
400badly formattednumber. -
415invalidtransport. -
413rate limit exceeded. Too many requests.
PUT /v1/acccounts/code/{verification_code}
Authorization: Basic {basic_auth}
{
"signalingKey" : "{base64_encoded_52_byte_key}",
"supportsSms" : false,
"registrationId" : "{14-bit number}"
}
The client submits the verification code it received via voice or SMS to the server for confirmation.
-
verification_codeis the code it received via voice or SMS, numeric only. -
basic_authare the authorization credentials the client would like to create. These are in the form ofBase64({number}:{password}), wherenumberis the client's verified PSTN number andpasswordis a randomly generated 16 byte ASCII string. -
signalingKeyis a randomly generated 32 byte AES key and a 20 byte HMAC-SHA1 MAC key, concatenated together and Base64 encoded. -
supportsSmsindicates whether a client supports SMS as a transport. -
registrationIdis a 14 bit integer that's randomly generated at client install time. This will be used for clients to detect whether an app has reinstalled and lost their session state.
Returns:
-
200account successfully verified. -
401badly formattedbasic_auth. -
403incorrectverification_code. -
413rate limit exceeded. -
417number already registered.
PUT /v1/accounts/apn/
Authorization: Basic {basic_auth}
{
apnRegistrationId: "{apn_registration_id}"
}
or
PUT /v1/accounts/gcm/
Authorization: Basic {basic_auth}
{
gcmRegistrationId: "{gcm_registration_id}"
}
The client submits its APN or GCM push registration ID.
-
basic_authis the client's authorization credentials (see above). -
gcm_registration_idorapn_registration_idis the client's registration ID.
Returns:
-
200request succeeded. -
401invalid authentication credentials. -
415badly formatted JSON.
To unregister from the server, send the same request with method DELETE.
PUT /v1/keys/
Authorization: Basic {basic_auth}
{
lastResortKey : {
keyId: 0xFFFFFF
publicKey: "{public_key}"
identityKey: "{identity_key}"
},
keys: [
{
keyId: {key_id},
publicKey: "{public_key}",
identityKey: "{identity_key}"
},
...]
}
-
public_keyis a randomly generated Curve25519 public key with a leading byte of0x05to indicate its type. This is a total of 33 bytes, base64 encoded without padding (no ==). -
identity_keyis a Curve25519 public key with a leading byte of0x05to indicate its type. This is a total of 33 bytes, base64 encoded without padding (no ==). Each client should have a single identity key generated at install time. -
key_ideach prekey has a unique 24bit identifier. The last resort key is always 0xFFFFFF.
Returns:
-
200request succeeded. -
401invalid authentication credentials. -
415badly formatted JSON.
PUT /v1/directory/tokens
Authorization: Basic {basic_auth}
{
"contacts": [ "{token}", "{token}", ..., "{token}" ]
}
-
tokenis Base64(SHA1(E164number)[0:10]) without Base64 padding.
Returns:
-
400badly formatted token(s). -
401invalid authentication credentials. -
415badly formatted JSON. -
200request succeeded. The structure below is returned.
{
contacts: [{token="{token}", relay="{relay}", supportsSms="true"},
{token="{token}"},
...,
{token="tokenN", relay="{relay}"}]
}
-
tokenis Base64(SHA1(E164number)[0:10]) without Base64 padding. -
relayis the name of a federated node which this contact is associated with. -
supportsSmsindicates that the contact supports the SMS transport.
At this point the client should be fully registered.
Messages bodies sent and received by clients are a protocol buffer structure:
message PushMessageContent {
message AttachmentPointer {
optional fixed64 id = 1;
optional string contentType = 2;
optional bytes key = 3;
}
message GroupContext {
enum Type {
UNKNOWN = 0;
UPDATE = 1;
DELIVER = 2;
QUIT = 3;
}
optional bytes id = 1;
optional Type type = 2;
optional string name = 3;
repeated string members = 4;
optional AttachmentPointer avatar = 5;
}
enum Flags {
END_SESSION = 1;
}
optional string body = 1;
repeated AttachmentPointer attachments = 2;
optional GroupContext group = 3;
optional Flags flags = 4;
}
If a client does not have an existing session with a recipient, the client will need to retrieve a PreKey for the recipient in order to start one.
GET /v1/keys/{number}/{device_id}?relay={relay}
Authorization: Basic {basic_auth}
-
numberis the number of the recipient. -
device_idis the device id of the recipient, or*for all devices. -
relay(optional) is the federated relay the recipient is associated with. Therelayparam should only be included if the destination is at a federated node other than the sender.
Returns:
-
401invalid authentication credentials. -
413rate limit exceeded. -
404unknown/unregisterednumber. -
200request succeeded. The structure below is returned.
{
"keys" : [
{
"deviceId": {device_id},
"keyId": {key_id},
"publicKey": "{public_key}",
"identityKey": "{public_key}"
},
...
]
}
PUT /v1/messages/{destination_number}
Authorization Basic {basic_auth}
{
relay: "{relay}",
messages: [{
type: {type},
destinationDeviceId: {destination_device_id},
destinationRegistrationId: {destination_registration_id},
body: "{base64_encoded_message_body}", // Encrypted PushMessageContent
timestamp: "{time_sent_millis_since_epoc}"
},
...,
]
}
-
destination_numberis the PSTN number of the message recipient. -
relay(optional) is the relay the message recipient is registered with. -
typeis the type of message. Supported types are enumerated below. -
destination_device_idis the target device the message corresponds to for thedestination_number. -
bodyis the Base64 encoded (without padding) and encryptedPushMessageContent(above). -
timestamp_sent_millis_since_epochis the timestamp of the message in millis since the epoch.
Returns:
-
401invalid authentication credentials. -
409mismatched devices. -
410stale devices. -
413rate limit exceeded. -
415badly formatted JSON. -
200request succeeded.
409 Mismatched Devices:
This return code indicates that the devices in messages do not match the registered devices for destination_number. The response body indicates the mismatch:
{
missingDevices: [{missing_device_id}, {another_missing_device_id}, ...],
extraDevices: [{device_id_doesnt_exist}, ...]
}
410 Stale Devices:
This return code indicates that a target device has re-installed and the requesting client is sending a message for a stale session. The response body indicates which devices are effected:
{
staleDevices: [{stale_device_id}, ...]
}
APN clients will receive a push notification:
{
alert: "You have a new message!",
"m": "{payload}"
}
GCM clients will receive a push notification:
{payload}
-
payloadis a Base64 encoded (without padding)IncomingPushMessageSignal, which is encrypted and MAC'd using thesignalingKeysubmitted during registration.
Encrypted IncomingPushMessageSignal format:
struct {
opaque version[1];
opaque iv[16];
opaque ciphertext[...]; // The IncomingPushMessageSignal
opaque mac[10];
}
The IncomingPushMessageSignal protocol buffer:
message IncomingPushMessageSignal {
enum Type {
UNKNOWN = 0;
CIPHERTEXT = 1;
KEY_EXCHANGE = 2;
PREKEY_BUNDLE = 3;
PLAINTEXT = 4;
}
optional Type type = 1;
optional string source = 2;
optional uint32 sourceDevice = 7;
optional string relay = 3;
optional uint64 timestamp = 5;
optional bytes message = 6; // Contains an encrypted PushMessageContent
}
Recall that a push message is transmitted as the following structure:
message PushMessageContent {
message AttachmentPointer {
optional fixed64 id = 1;
optional string contentType = 2;
optional bytes key = 3;
}
message GroupContext {
enum Type {
UNKNOWN = 0;
UPDATE = 1;
DELIVER = 2;
QUIT = 3;
}
optional bytes id = 1;
optional Type type = 2;
optional string name = 3;
repeated string members = 4;
optional AttachmentPointer avatar = 5;
}
enum Flags {
END_SESSION = 1;
}
optional string body = 1;
repeated AttachmentPointer attachments = 2;
optional GroupContext group = 3;
optional Flags flags = 4;
}
To fill out the AttachmentPointer structure, the client takes the following steps:
- Generates a single-use 32 byte AES key and 32 byte Hmac-SHA256 key.
- Encrypts the attachment using AES in CBC mode with PKCS#5 padding and a random IV, then formats the encrypted blob as
IV || Ciphertext || MAC. - Requests an attachment allocation from the server.
- Uploads the attachment to the allocation.
- Constructs the
AttachmentPointerwith the attachment allocationid, the attachment's MIMEcontentType, and the concatenated 32 byte AES and 32 byte Hmac-SHA256key.
GET /v1/attachments/
Authorization: {basic_auth}
Returns:
-
401invalid authentication credentials. -
413rate limit exceeded. -
200request succeeded. The structure below is returned.
{
"id" : "{attachment_id}",
"location" : "{attachment_url}"
}
PUT {attachment_url}
Content-Type: application/octet-stream
The client PUTs the encrypted binary blob to the attachment_url returned from the attachment allocation step.
GET /v1/attachments/{attachment_id}
Authorization: {basic_auth}
-
attachment_idis theidin a receivedAttachmentPointerprotocol buffer.
Returns
-
401invalid authentication credentials. -
413rate limit exceeded. -
200request succeeded. The structure below is returned.
{
"location" : "{attachment_url}"
}
The client can now GET {attachment_url} to retrieve the encrypted binary blob.