Skip to content

Connector API

CEO itself is a headless CMS based around a robust API. As a headless CMS it has a number of was of notifying front end systems of changes.

One of the easiest to integrate is the Connector. The receiving end must be able to:

  1. Process and verify JWT.
  2. Process and parse JSON data.

First, tell CEO where to send your data

You'll need to update the ceo-core config with your new endpoint. When looking at that config file, you should see something like:

'connector' => [
    [
        'key'       => "MY-KEY",
        'url'       => 'https://my.site.tld/ceo/connector/',
    ]
],

To add a second endpoint, update the key to connectors and send it an array of configuration options:

'connectors' => [
    [
        'key' => 'MY-KEY',
        'url' => 'https://my.site.tld/ceo/connector/'
    ],
    [
        'key' => 'MY-OTHER-KEY',
        'url' => 'https://my.othersite.tld/some/endpoint'
    ]
]

The value of key will be used to sign and verify your JWT, so treat that like a password and ensure it's sufficiently random.

Custom Connectors

It's possible to leverage connectors to push data to other authenticated endpoints, for example, Apple News:

'connectors' => [
    [
        'key' => 'pub:priv',
        'url' => 'none',
        'connector' => \Ceo\Core\Connectors\AppleNewsConnector::class
    ]
]

Wait for the data to roll in

Every time content, containers, channels or entires are updated in CEO, your connector endpoint will see POST data. Keep in mind that changes can come quickly, so you may want to implement mutex transactions to keep from running into race conditions.

There are two components to each webhook call. First is the JWT and the second is the post data.

JWT

The JWT is used to authenticate the transaction, it allows you to be sure that the data came from CEO and not an outside source.

CEO passes the JWT as a Bearer Authorization header.

Verify that the signer used the same shared key configured above, that it's not expired, and the Audience is your endpoint.

Additionally, the following Claims will be set:

  • action - one of create, update, or delete
  • srn - the object's unique identifier

JSON Data

The JSON data will be transmitted via the POST body. It follows the same format as all API data. Examples are provided in the API docs.

Example

A full example may take the form of:

POST /my/endpoint HTTP/1.1
Content-Type: application/json
Authorization: Bearer XXXXXXXX
{
    "id": "9999",
    "uuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "title": "...",
    "slug": "...",
    "type": "article",
    "version": "2",
    "weight": "0",
    "abstract": "",
    "abstract_raw": "",
    "content": "...",
    "content_raw": "...",
    "created_at": "YYYY-MM-DD HH:MM:SS",
    "modified_at": "YYYY-MM-DD HH:MM:SS",
    "published_at": null,
    "state": "0",
    "url_id": null,
    "assignment_id": null,
    "title_url": "...",
    "seo_title": "",
    "seo_description": "",
    "seo_url": "",
    "layout_template": null,
    "click_through": null,
    "srn": "srn:snw:ceo-core/content:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "export": {
        ...
    },
    "authors": [
        {
            ...
        }
    ],
    "tags": [
        ...
    ],
    "user": {
        ...
    },
    "urls": [],
    "lock": false,
    "versions": [
        ...
    ],
    "audit": [
        ...
    ],
    "relatedContent": [
        ...
    ],
    "keywords": [
        ...
    ],
    "ssts_path": "..."
}