Fork me on GitHub

REST API Specification

The Ably REST API provides a way for a wide range of server and client devices to communicate with the Ably service over REST. The REST API does not provide a real-time connection to Ably, but in all other respects is a simple subset of the full real-time messaging API.

The primary use-case for the REST API is for servers that are part of the back-end of an application such as a web application, that publish messages, issue access tokens (temporary and client-specific) for its various clients, and obtain message history.

The functional scope of the REST API includes:

Ably also provides REST client libraries for a range of languages including Javascript, Java, Python, Ruby, .NET.

Common API behaviour

General

The REST API defaults to returning results, and expects request bodies, in JSON format. An Accept header is used to specify a specific response format – JSON or an alternative – and the following formats are allowed:

It is also possible to specify the response format with the format query parameter (with supported values being json, jsonp, binary, html). Any Accept header takes precedence over a format parameter.

Similarly, POST requests may contain a request body in JSON or other formats as indicated by a Content-Type header. The supported content types are:

Specific request and response data types are documented in the context of each API or route.

A response status code of 20X (200, 201 or 204) indicates success. A successful result will typically provide a response body but certain operations (such as DELETE) may respond with a 204 response and no response body.

All other standard HTTP statusCodes signify an error. Errors from all APIs are returned as an object of the form:

{
  error: {
    code: <ably error code>,
    message: <string>,
    statusCode: <http status code>
  }
}

The properties of error are:

code
A specific reason code as defined in the public errors definition (link TBD), where one is known
statusCode
Where a code is not available, the statusCode provides a generic indication of the nature of the failure
message
The message string is an English language string that aims to provide useful information to the developer. It is not necessarily intended to be an informative string for the end user

Wherever possible, success response bodies contain links, in HATEOS style, to other resources relevant to the response; where these are present these are included as href attributes on the applicable part of the response object.

GET, PUT, POST and DELETE are available in all contexts where they make sense. GET is always idempotent.

Pagination

REST APIs whose responses may have unbounded size have paginated responses; that is, if a full response to the query could exceed a limit (a default or a limit given as a parameter to the call) the first response contains a subset of the results, and further “pages” of the result are available on subsequent requests. Each response (the initial response and responses to each subsequent request) is accompanied by one or more relative links relating to the current query.

Responses contain one or more of the following relative links:

first
a link to the first page of results for this query. This link also makes the query repeatable; any params that are resolved at query time (for example default values for omitted time-related params) have their resolved values included explicitly in the first link.
current
a stable link to the current page of results.
next
on each page except the last in a paginated result, the next link is a link to the next page of results.

Relative links are presented by default as an RFC 5988 Link HTTP response header; there is a separate Link header for each relative link accompanying the response. The rel types used are first, next and current as specified in the RFC.

A Link header has the format:

Link: <<url>>; rel=“<rel>”

where <url> is the URL of the link and <rel> is the relation type.

For example:

Link: <./stats?start=1380794880000&end=1380794881058&limit=100&unit=minute&direction=forwards
&format=json&first_start=1380794880000>; rel=“first”

In principle the link URL might be any valid URL but in practice it will always be a relative URL, and it must be interpreted relative to the original query URL. Clients should treat link URLs opaquely; in particular, params (such as first_start in the example above) may be undocumented and unsupported except where a client uses the link URL in its entirety.

Clients that are unable to process response headers may also request an envelope response type.

Envelope response format

A client that is unable to access response headers or status code can request an envelope response that contains the usual response, plus Link header information and the response status code wrapped in an object as a single response body. This is useful for JSONP and may be useful in other environments. Envelope responses are only supported for JSON, JSONP and HTML formats.

A client requests an envelope response by including an envelope=true param in the request.

An envelope response body then has the format:

{
    "statusCode": <status code>,
    "response": <result of API call>,
    "rel": {
        "first": <URL>,
        ...
    }
}

where the response member references the API result in the usual format. The rel member, present only in paginated responses, includes each of the rel links associated with the response.

Envelope responses always are always made with a 200 status code; the status of the API request itself must be obtained from the statusCode member of the response body.

Authentication

To understand the REST API it is easiest first to understand the various authentication methods that Ably supports.

Clients can access Ably, whether using REST or the Real-time service, by two methods.

Basic Authentication

Using one of the application keys created via the application dashboard. Basic Authentication is the simplest method to use but has two important limitations:

Usage in HTTP request header

Authorization: Basic <Base64-encoded key>

where <Base64-encoded key> is the full application key string obtained through the dashboard, encoded with RFC 4648 Base64.

When using a generic HTTP client library that accepts separate username and password arguments for an HTTP request, the application key can be split at the first colon, with the initial segment being used as the username, and the remaining string (without the leading colon) used as the password.

Token Authentication

Using a token obtained via the REST API requestToken endpoint. Tokens are authentication tokens that only have a short lifetime, and therefore they may more readily be distributed to clients where there is a risk of compromise. Tokens may also be issued with a particular scope – such as a limited set of access rights, or being limited to use by a specific client – and therefore token-based authentication provides the flexibility to implement access control policies in the application. See Authentication for more details.

The requestToken endpoint may be used without explicit authentication, relying on the implicit authentication of submitting a validly signed token request.

Usage in HTTP request header

Authorization: Bearer <token string>

The <token string> does not need to be encoded or escaped. If using a generic HTTP client library it will probably be necessary to add the Authorization header explicitly.

API routes

Channel routes

Routes providing access to the messaging service within a channel scope.

Publish one or more events on a channel

POST /channels/<channel id>/messages

Publish a message on a channel. Note that since the REST API is stateless, publication using this API is of single messages, outside the context of any specific connection.

The request body contains message details and is an object of the form:

{
  name: <event name>,
  data: <message payload>
}

In JSON format, the accepted types for the data payload are:

Parameters

None

Options
Alternative paths
GET /channels/<channel id>/publish
Request body
JSON or formformat, see above.
Content-Type
application/json or application/x-www-form-urlencoded
Accept
not applicable
Auth required
yes (basic or token)
Returns

Nothing

Retrieve message history for a channel

GET /channels/<channel id>/messages
Parameters
start
beginning of time The start of the query interval as a time in milliseconds since the epoch. A message qualifies as a member of the result set if its system timestamp (not necessarily the same as a timestamp applied by the client before submission) is equal to, or greater than, this time.
end
now The end of the query interval as a time in milliseconds since the epoch. A message qualifies as a member of the result set if its system timestamp is equal to, or less than, this time.
limit
100 The maximum number of records to return. A limit greater than 10000 is invalid.
direction
backwards The direction of this query. The direction determines the order of the returned result array, but also determines which end of the query interval is the start point for the search.
by
message One of the values message, bundle or hour:
If message, the result is an array of individual message records containg the message data together with message metadata.
If bundle, the result is an array of references to message ‘bundles’, which are the unit of persistence of channel messages.
If hour, the result is an array of references to (channel + hour) pairs, signifying those channels and times during which there were messages within the query interval.
Options
Alternative paths
GET /channels/<channel id>/history
Request body
not applicable
Content-Type
not applicable
Accept
application/json by default, or text/html, text/xml
Auth required
yes (basic or token)
Returns

In each case a successful result is an array containing the items that match the query (and it may be empty).

In the case of a message query, each member is a message object of the form:

{
  name: <event name>,
  channel: <channel id>,
  data: <message payload>,
  timestamp: <message timestamp>
}

In the case of a bundle query, each member is a bundle reference. (Detailed description TBD.)

In the case of an hour query, each member is a channel/hour reference. (Detailed description TBD.)

Retrieve instantaneous presence status for a channel

GET /channels/<channel id>/presence

Obtain the set of members currently present for a channel.

Parameters

None

Options
Alternative paths
GET /channels/<channel id>/presence
Request body
not applicable
Content-Type
not applicable
Accept
application/json by default, or text/html, application/x-thrift, text/xml
Auth required
yes (basic or token)
Returns

A successful request returns an array containing the members that are currently present on the given channel. If there are no members present, an empty collection is returned.

JSON response bodies are arrays with each member being a presence-message object of the form:

{
  state: <presence state>,
  clientId: <member client id>,
  memberId: <a unique member identifier>,
  clientData: <message payload>,
  timestamp: <message timestamp>
}

Thrift response bodies are instances of TPresenceArray encoded using the Thrift binary encoding.

Retrieve presence history for a channel

GET /channels/<channel id>/presence/history

Obtain the history of presence messages for a channel.

Parameters
start
beginning of time The start of the query interval as a time in milliseconds since the epoch. A message qualifies as a member of the result set if its system timestamp (not necessarily the same as a timestamp applied by the client before submission) is equal to, or greater than, this time.
end
now The end of the query interval as a time in milliseconds since the epoch. A message qualifies as a member of the result set if its system timestamp is equal to, or less than, this time.
limit
100 The maximum number of records to return. A limit greater than 10000 is invalid.
direction
backwards The direction of this query. The direction determines the order of the returned result array, but also determines which end of the query interval is the start point for the search.
Options
Alternative paths
GET /channels/<channel id>/messages?type=presence
Request body
not applicable
Content-Type
not applicable
Accept
application/json by default, or text/html, application/x-thrift, text/xml
Auth required
yes (basic or token)
Returns

A successful request returns an array containing the members that are currently present on the given channel. If there are no members present, an empty collection is returned.

JSON response bodies are arrays with each member being a presence-message object of the form:

{
  state: <presence state>,
  clientId: <member client id>,
  memberId: <a unique member identifier>,
  clientData: <message payload>,
  timestamp: <message timestamp>
}

Thrift response bodies are instances of TPresenceArray encoded using the Thrift binary encoding.

Authentication

Request an access token

POST /keys/key id/requestToken

This is the means by which clients obtain access tokens to use the service. The construction of a token request is described in the Authentication page. The resulting token response object contains the token properties as defined in Authentication.

Parameters

None

Options
Request body
signed or unsigned token request
Content-Type
text/plain
Accept
application/json
Auth required
no (for signed token requests), yes (basic or token for unsigned token requests)
Returns

<token response>

Application routes

Routes providing access to the messaging service within an application scope.

Retrieve usage statistics for an application

GET /stats

The Ably system can be queried to obtain usage statistics for a given application, and results are provided aggregated across all channels in use in the application in the specified period. Stats may be used to track usage against account quotas.

Stats queries are made by specifying a query interval and the granularity expected in the results. The query interval is expressed as a start and end time, each being a timestamp in milliseconds since the epoch. Stats are aggregated by the system in ‘subminute’ intervals of 6s (ie 0.1m), so query interval start and end times are rounded down to the nearest subminute boundary.

Parameters
start
beginning of time The start of the query interval as a time in milliseconds since the epoch.
end
now The end of the query interval as a time in milliseconds since the epoch.
limit
100 The maximum number of records to return. A limit greater than 10000 is invalid.
direction
backwards The direction of this query. The direction determines the order of the returned result array, but also determines which end of the query interval is the start point for the search.
unit
minute One of the values minute, hour, day or month, specifying the unit of aggregation in the returned results.
Options
Request body
not applicable
Content-Type
not applicable
Accept
application/json by default, or text/html, application/x-thrift, text/xml
Authentication required
yes (basic or token)
Returns

In each case a successful result is an array containing the items that match the query (and it may be empty).

Stats records contain a hierarchy of elements relating to messages, connections and other resources consumed in an interval. An example of a full stats record is given below. Any single record may contain a subset of the elements, omitting empty sections.

{
  "all": {
    "all": { "count": 354, "data": 27200 },
    "messages": { "count": 354, "data": 27200 },
    "presence": { "count": 0, "data": 0 }
  },
  "inbound": {
    "all": {
      "all": { "count": 130, "data": 10318 },
      "messages": { "count": 130, "data": 10318 },
      "presence": { "count": 0, "data": 0 }
    },
    "realtime": {
      "all": { "count": 130, "data": 10318 },
      "messages": { "count": 130, "data": 10318 },
      "presence": { "count": 0, "data": 0 }
    },
    "rest": {
      "all": { "count": 0, "data": 0 },
      "messages": { "count": 0, "data": 0 },
      "presence": { "count": 0, "data": 0 }
    },
    "push": {
      "all": { "count": 0, "data": 0 },
      "messages": { "count": 0, "data": 0 },
      "presence": { "count": 0, "data": 0 }
    },
    "httpStream": {
      "all": { "count": 0, "data": 0 },
      "messages": { "count": 0, "data": 0 },
      "presence": { "count": 0, "data": 0 }
    }
  },
  "outbound": {
    "all": {
      "all": { "count": 224, "data": 16882 },
      "messages": { "count": 224, "data": 16882 },
      "presence": { "count": 0, "data": 0 }
    },
    "realtime": {
      "all": { "count": 206, "data": 16074 },
      "messages": { "count": 206, "data": 16074 },
      "presence": { "count": 0, "data": 0 }
    },
    "rest": {
      "all": { "count": 18, "data": 808 },
      "messages": { "count": 18, "data": 808 },
      "presence": { "count": 0, "data": 0 }
    },
    "push": {
      "all": { "count": 0, "data": 0 },
      "messages": { "count": 0, "data": 0 },
      "presence": { "count": 0, "data": 0 }
    },
    "httpStream": {
      "all": { "count": 0, "data": 0 },
      "messages": { "count": 0, "data": 0 },
      "presence": { "count": 0, "data": 0 }
    }
  },
  "persisted": {
    "all": { "count": 473, "data": 37914 },
    "messages": { "count": 473, "data": 37914 },
    "presence": { "count": 0, "data": 0 }
  },
  "connections": {
    "all": { "opened": 0, "peak": 0, "mean": 0, "min": 0, "refused": 0 },
    "plain": { "opened": 0, "peak": 0, "mean": 0, "min": 0, "refused": 0 },
    "tls": { "opened": 0, "peak": 0, "mean": 0, "min": 0, "refused": 0 }
  },
  "channels": { "opened": 22, "peak": 0, "mean": 0, "min": 0, "refused": 0 },
  "apiRequests": { "succeeded": 6, "failed": 0, "refused": 0 },
  "tokenRequests": { "succeeded": 0, "failed": 0, "refused": 0 },
  "count": 0,
  "intervalId": "2013-10-31:22:10",
}

Utilities

Get the service time

GET /time

This returns the service time in milliseconds since the epoch. This may be used by clients that do not have local access to a sufficiently accurate time source when generating a token request. (Token requests include a timestamp and have a limited validity period to help defend against replay attacks.)

The result is a JSON-encoded array of length 1 containing the time result as a number.

Parameters

None

Options
Request body
not applicable
Content-Type
not applicable
Accept
application/json
Auth required
no
Returns
[ <time> ]

Back to top