API

The Cloud CMS API consists of an HTTP/HTTPS endpoint that uses OAuth 2.0 authentication. It supports both REST
concepts and asynchronous data operations. You can access this API using any of our drivers as well as
curl or any HTTP client library.

Our API provides functionality that covers all aspects of content production, publishing and presentation. 100% of
the functionality of Cloud CMS is accessible from the API, including:

  • Content Models, Creation and Editing
  • Workflow, Scheduled Publishing and Release Management
  • Users and Groups Management
  • Role-based Authorities and ACL Security
  • Binary Files and Attachments
  • Versioning, Branching with Fork and Merge
  • Query, Search, Traversal and Find Operations
  • Replication and Content Transfer
  • Data Warehouses and Analytics Capture

And much more.

The goal of this guide is to provide deeper information into the API, its object types and data stores that go
beyond what is available in the developer Getting Started section and the API Explorer.

API Keys

Each Cloud CMS tenant may create as many API Key sets as they wish. To generate API keys, navigate into a Project
and then create an Application. Each Application comes with its own set of API Keys.

You can view API Keys for a Project or for your entire Platform (across all Projects) by using the API Keys page
on the left-hand navigation.

[object Object]

Your API keys appear along with links to download driver files:

[object Object]

For information on API Keys, please visit API Keys

Authentication

Cloud CMS is a HTTPS API that uses OAuth 2.0 for user assertion. Every request into Cloud CMS requires a OAuth 2.0
access token (a bearer token). There are no anonymous requests - user identity is asserted and access rights are
checked for all services and objects accessed with every call.

For information on OAuth 2.0 authentication within Cloud CMS, please see our documentation on Authentication.

Endpoints

Cloud CMS is provided as a SaaS offering that is available at the following endpoint:

https://api.cloudcms.com

All requests are served over HTTPS.

On-premise installations can have any endpoint that they prefer. On-premise customers are required to manage their own
DNS, routes and SSL certificates.

Formats

Cloud CMS supports JSON and binary attachment storage (Word, PDF, audio, video, etc). Binary files that are uploaded
are interrogated and extracted from. JSON is the primary storage format and the primary format for API requests and
responses.

Rate Limiting

Cloud CMS SaaS tenants are configured for rate limiting. This limits the number of concurrent requests that may
be executed against the Cloud CMS API per tenant.

For more information on rate limiting, please see:

Rate Limiting

System Dates

Cloud CMS managed dates (such as creation date, modification date, release dates, etc) are stored as timestamp objects
which have the following structure:

{
    "timestamp": "01-Jan-1970 00:00:00",
    "year": 1970,
    "month": 0,
    "day_of_month": 1,
    "hour": 0,
    "minute": 0,
    "second": 0,
    "millisecond": 1,
    "ms": 1,
    "iso_8601": "1970-01-01T00:00:00Z"
}

The timestamp field provides a friendly, human readable value for the time. The components of the time are then
broken out by individual fields where all fields are 0-indexed except for the day of the month. The ms field
provides the elapsed milliseconds since timestamp or unix epoch counting from 1 January 1970. And the iso_8601 field
provides an ISO 8601 formatted value for the time.

Request

Cloud CMS API responses are optimized to be thin by default. The goal is keep the response payload over the wire
pretty thin so as to reduce network latency.

There are a few interesting ways that you can control the response payload using request parameters. A barebones
skinny payload response may look like:

{
    "_doc": "d0977d2194dfcb8eec61"
}

For single item responses, you will additionally get back any custom properties you have defined. For collections,
if you pass in ?full=true, you will get back the full object instead of just an empty shell with the _doc field:

{
    "_doc": "d0977d2194dfcb8eec61",
    "_type": "my:article",
    "_qname": "o:d0977d2194dfcb8eec61",
    "title": "Hello World",
    "description": "Share and Enjoy"
}

If you pass in ?metadata=true, you will additionally get back system metadata:

{
    "_doc": "d0977d2194dfcb8eec61",
    "_type": "my:article",
    "_qname": "o:d0977d2194dfcb8eec61",
    "title": "Hello World",
    "description": "Share and Enjoy",
    "_system": {
        "timestamp": "01-Jan-1970 00:00:00",
        "year": 1970,
        "month": 0,
        "day_of_month": 1,
        "hour": 0,
        "minute": 0,
        "second": 0,
        "millisecond": 1,
        "ms": 1,
        "iso_8601": "1970-01-01T00:00:00Z"
    }
}

If you pass in ?paths=true, you will also get back path information:

{
    "_doc": "d0977d2194dfcb8eec61",
    "_type": "my:article",
    "_qname": "o:d0977d2194dfcb8eec61",
    "title": "Hello World",
    "description": "Share and Enjoy",
    "_system": {
        "timestamp": "01-Jan-1970 00:00:00",
        "year": 1970,
        "month": 0,
        "day_of_month": 1,
        "hour": 0,
        "minute": 0,
        "second": 0,
        "millisecond": 1,
        "ms": 1,
        "iso_8601": "1970-01-01T00:00:00Z"
    },
    "_paths": [
        "821c40ab613d9b5bcbbc656b62229301": "/My/Folder"
    ]
}

Cloud CMS allows for multiple mount points and the _paths array will contain the paths for each mount point. The
value 821c40ab613d9b5bcbbc656b62229301 is the ID of the repository branch's root folder.

If you pass in ?locale={locale}, you can force the locale of the content served back in the response. This requires
that your content have the f:multilingual feature applied to it and that it have some translations. For example,
if your content has a translation available for zh_CN (Simplified Chinese), you could add ?locale=zh_CN and get back:

{
    "_doc": "d0977d2194dfcb8eec61",
    "_type": "my:article",
    "_qname": "o:d0977d2194dfcb8eec61",
    "title": "你好,世界",
    "description": "分享与享受"
}

For more information on internationalization (I18N), see Internationalization.

Pagination

You can use the following request parameters to control pagination of record sets / collections with multiple items:

  • skip - the index to begin serving content back from within the result set (default is 0)
  • limit - the maximum number of items to serve back
  • sort - the sorting to apply to the look up

For more information, see Pagination.

Response Codes

HTTP status codes are used to indicate the success or failure of the HTTP call. These response codes follow HTTP
convention. The most common error codes are:

</tbody>
Code Status Description
200 Success The request completed successfully and you are being given back the results
301 Redirect The requested resource exists somewhere else and the response is being redirected to that location
400 Bad or malformatted request The request could not be understood by the Cloud CMS API and so it was rejected
401 Unauthorized The request does not have a valid bearer token. Thus, an authenticated user could be established. Cloud CMS does not allow for anonymous access and so the request is being rejected.
403 Access Denied The request has a valid bearer token and authenticated user but the user does not have sufficient access rights to access the resource
404 Resource not found The request is for a resource that does not exist
405 Method not allowed The request specified an HTTP method (for example, POST or PUT) that isn't allowed (for example, when the API call only accepts GET)
429 Rate Limited Error The request is from a tenant that has exceeded its maximum number of concurrent connections
500 Internal Server Error An error occurred while processing the request
504 Gateway Timeout The request took too long to process. This indicates that the request is still executing on the server. It hasn't finished but the API was forced to abandon the call and return early (because the call was taking too long)

Response Envelopes

The API returns one of three envelopes depending upon the request issued:

  1. Single item envelope
  2. Collections envelope
  3. Error envelope

Single Item Envelope

At a minimum, the returned item will contain the _doc field. This field is the primary ID of the object or datastore
being requested. In Cloud CMS, the _doc field is always the primary key field.

{
    "_doc": "d0977d2194dfcb8eec61"
}

You may additionally get other properties, depending what you request. All other properties are entity-specific.

An example:

{
    "_doc": "d0977d2194dfcb8eec61",
    "_type": "my:article",
    "_qname": "o:d0977d2194dfcb8eec61",
    "title": "Hello World",
    "description": "Share and Enjoy"
}

Collections Envelope

When you run queries, search or traversals or when you pull back children, relatives or perform other lookups into
the content graph or into a datastore, you may get back multiple results. These return a result sets (or Collections).

Each result set / collection has a rows array containing the _doc fields for each result. They also have size
which provides the total number of rows in the current result set. The total_rows field indicates how many
matches there are in total and the offset field indicates the starting cursor location for the returned set.

The size, total_rows and offset fields provide back pagination information about the view of the current set
of results being handed back. These work hand-in-hand with the skip, limit and sort pagination options on the
request to provide sorting and pagination.

{
    "rows": [{
        "_doc": "d0977d2194dfcb8eec61"
    }, {
        "_doc": "d0977d2194dfcb8eec62"
    }],
    "size": 2,
    "total_rows": 4,
    "offset": 0
}

If you pass in the request parameter ?full=true, you will get back the full objects (instead of just skinny objects
with nothing more than the _doc fields).

{
    "rows": [{
        "_doc": "d0977d2194dfcb8eec61",
        "_type": "my:article",
        "_qname": "o:d0977d2194dfcb8eec61",
        "title": "Hello World",
        "description": "Share and Enjoy"
    }, {
        "_doc": "d0977d2194dfcb8eec62",
        "_type": "my:article",
        "_qname": "o:d0977d2194dfcb8eec62",
        "title": "Saas that hoopy",
        "description": "There's a frood who really knows where his towel is"
    }],
    "size": 2,
    "total_rows": 4,
    "offset": 0
}

Error Envelope

If an error occurs on a call, the appropriate HTTP response code will be set and a JSON object will be handed back with
additional information about what went wrong.

{
    "ok": false,
    "error": true,
    "message": "You are not permitted to access this resource"
}

Cache Headers

All requests to the Cloud CMS API itself are served back with response headers that are designed to eliminate
upstream caching by proxy servers or CDNs.

The headers frequently come back like this:

cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0

The reason we do this is because the Cloud CMS API itself is dynamic and the resources within the API are ever-changing.
It would be far from ideal if a user were to modify a content item in Cloud CMS and then retrieve a cached version
where their changes were not present on the next read.

While the Cloud CMS API sets its headers so as to be fully dynamic, this does not preclude your own applications or
your own proxy servers or CDNs from caching. Rather, the onus and discretion of how to do this is handed to the
customer and their applications.

Cloud CMS does not impose a one-size fits all caching strategy. Our experience is that every customer is unique
and so we leave it open to them to cache as they see fit.

If you're looking for a caching middle-tier solution, we recommend taking a look at the Cloud CMS Application Server
as it provides caching and CDN-friend cache headers out-of-the-box. It sits between your front-end application
and the Cloud CMS API back end and provides an ideal solution for cache management.

HEAD Requests

Cloud CMS supports HTTP HEAD requests to allow you to retrieve pre-flight options regarding the resource being
requested. The response from a HEAD request is light in that it doesn't include a response payload. Instead,
it is primarily used to retrieve response headers that inform the caller about the resource.

The response headers might look something like this:

accept-ranges: bytes
content-type: application/json;charset=utf-8
content-length: 319

In addition, you will get back CORS headers that might look like something like this:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: X-Forwarded-Host, X-Requested-With, Content-Type, Authorization, Origin, X-Requested-With, X-Prototype-Version, Cache-Control, Pragma, X-CSRF-TOKEN, X-XSRF-TOKEN
Access-Control-Allow-Credentials: true

Note that Cloud CMS supports a wildcard on the CORS origin header. If you'd like to constrain this for the
purposes of your application needs, we recommend using a middle-tier solution such as the Cloud CMS Application Server.

Range Support

Recent versions of Cloud CMS support the HTTP Range header to allow you to specify the starting byte and ending byte
of one or more ranges to retrieve for a given resource. This enables Cloud CMS to be compatible with a broad set
of streaming and caching services that require multipart partial content loading to efficiently serve large
resource types (such as video and audio files).

Cloud CMS supports the range header across all of its GET API methods for reading resources. This includes
API methods that stream back binary attachments as well as API methods that read objects (as JSON payloads).

The accept-ranges response header comes back for every HEAD and GET request and will always have the value
of bytes indicating the ranges should be specified using starting and final byte indexes. The content-length
header indicates the total length of the content in bytes.

When the range header is used, the response payload will be truncated to the precise range of bytes that you request.
It's important to note that, by definition, this means that the response payload may not be structurally complete.
The burden is placed on the application developer to use ranges effectively to pull down "chunks" of a response and
reassemble them within the application.

Cloud CMS supports single and multiple range specifications.

Here are examples of how the range header can be used:

range: bytes=0-99
range: bytes=0-99,200-299
range: bytes=0-49,100-149,200-249,300-319

The first example (range: bytes=0-99) serves back the first 100 bytes of the resource. Note that the range delimitters
are inclusive meaning that the range starts (and includes) byte 0 and ends on (and includes) byte 99.

The second example (range: bytes=0-99,200-299) serves back two ranges. The first range is the first 100 bytes of the resource.
The second range is from byte 200 to byte 299.

The third example serves back four different ranges.

When using ranges, the starting range value must always be lower than the ending range value. In addition, a
starting and ending value is always required.

If you specify the range header, the response will come back with status code 206 (Partial Content).
It will include a content-range header that indicates the range of the response.

The content-range response headers might look like this:

content-range: bytes 0-99/319

This example might be what comes back for the first range header from above. It indicates that the payload
handed back consists of bytes 0 through 99 of 319 total.

If there is error with your range header, you will get back status code 416 (Requested Range Not Satisfiable).
You will also get back a content-range header that indicates what is valid.

It might look something like:

content-range: bytes */319

Single Range Requests

When you specify a single range, the response will come back in a non-multiple format.

The status code will be 206 indicating Partial Content.

Each part in the response will have the following headers:

  • content-type will be the content type of the resource (such as video/mp4 or application/json)
  • content-range will indicate the range of the served content, such as:

Multiple Range Requests

When you specify multiple ranges, the response will come back in a multipart response format where each part is one of the ranges.

The content-type will be multipart/byteranges; boundary=MULTIPART_BYTERANGES where the multipart
delimitter is indicated and has the value MULTIPART_BYTERANGES.

The status code will be 206 indicating Partial Content.

Each part in the response will have the following headers:

  • content-type will be the content type of the resource (such as video/mp4 or application/json)
  • content-range will indicate the range of the served content, such as:
content-range: bytes 0-99/319

This would indicate that this part contains 100 bytes (from index 0 through and including index 99) of the resource.
The total size of the resource is 319.

Example using CURL

First, we can make a HEAD call to check whether the Cloud CMS supports the range header for a given
JSON resource.

curl -I 'https://api.cloudcms.com/repositories/3b61d917c89cbcd40e5e/branches/1d69237eab15b2d3a3ad/nodes/cbd054cebc179a07ad31'

We get back the headers, including:

accept-ranges: bytes
content-type: application/json;charset=utf-8
content-length: 319

The accept-ranges header verifies that the Cloud CMS API accepts the range header.

Let's now retrieve two ranges from the response using the header range: bytes=0-99,200-299.

curl 'https://api.cloudcms.com/repositories/3b61d917c89cbcd40e5e/branches/1d69237eab15b2d3a3ad/nodes/cbd054cebc179a07ad31' -H 'range: bytes=0-99,200-299' \

And we get back something like

--MULTIPART_BYTERANGES
Content-Type: application/json; charset=utf-8
Content-Range: bytes 0-99/319
{"title":"Test","_type":"n:node","_doc":"cbd054cebc179a07ad31","_qname":"o:cbd054cebc179a07ad31","_
--MULTIPART_BYTERANGES
Content-Type: application/json; charset=utf-8
Content-Range: bytes 200-299/319
":{"a:child":1,"a:child_INCOMING":1,"a:has_role":1,"a:has_role_INCOMING":1},"_is_association":false
--MULTIPART_BYTERANGES--

Additional Range Support

Cloud CMS does not yet support the if-range header. This is on the roadmap and we are in the process
of triaging it.

Getting Started for Developers

In terms of getting started with Cloud CMS and the Cloud CMS API, we recommend visiting our
Cloud CMS Developers Page. These pages will guide you through
connecting to Cloud CMS for the first time, getting your API Keys and setting up an account if you haven't
already.

Cloud CMS API Explorer

The Cloud CMS API Explorer is a Swagger-based user interface that enables you to explore the Cloud CMS API from
within your web browser. Using the explorer, you can authenticate and then fire off methods one at a time using
the web interface.

The API Explorer is a good way to play around and try things. We also recommend using curl to fire methods by
hand. The Cloud CMS SDK provides several curl examples that you can use
as a starting point.

The Cloud CMS API Explorer also provides a Swagger compliant JSON file that you can use to potentially generate
your own client stub code. Check out the Swagger project for more information.

Cloud CMS Drivers

Cloud CMS also provides drivers for a variety of languages that you can use to interact with the API
programmatically. This can save you a lot of time, certainly, and can also inform your own custom development
in terms of having working code that you can build upon.

Further Reading