Content Management API

The Content Management API gives clients access to their Dari data models backed by the Java classes that define them. The API provides the same CRUD operations available when using the Dari Java APIs directly.

The API lives at the path /management/graphql and is only accessible on the CMS domain. This is the URL specified in Admin > Sites & Settings > Global > Default Tool URL. So, if that value is set to, then you can access this API by sending requests to An API key is required to access this endpoint, and that key may also have Site restrictions on it. If Site restrictions are present, then you must pass the ID of the Site with the request. It can either be passed as a query parameter in the URL named site or as a Header with the name X-BSP-SITE. If no restrictions exist, then you can freely access any content in the system.

Consider the content type defined by the following Java class:

package com.example;

import com.psddev.cms.db.Content;

public class Article extends Content {

    private String title;

    public String getTitle() {
       return title;

    public void setTitle(String title) {
        this.title = title;

Using the Dari Java APIs, you could create, update, read, and delete an Article with the following code:

public class Code {
    public static Object main() {
        // Create
        Article a = new Article();

        // Read
        a = Query.from(Article.class)
            .where("title = ?", "GraphQL")

        // Update

        // Delete

        return a.getTitle();

With the GraphQL API, all the CRUD operations above are strictly typed. This means that for each content type, there is a unique set of query and mutation fields that are used to manage that type. Using the Article example above, here is a snippet from the generated schema representing the APIs available to you for this type.

 type Query {
   Article(id: ID, path: String): Article
   ArticleQuery(predicate: String, sorts: [Sort!], offset: Int, limit: Int): ArticleQueryResult

 type Mutation {
   ArticleSave(object: ArticleInput): Article
   ArticleDelete(id: ID): Article

There are four operations that can be done for this type: two for reads and two for writes.

The Article and ArticleQuery fields are used to find content of that type. The Article field lets you look up a single Article content by its ID or permalink. The ArticleQuery field lets you search for multiple articles optionally supplying a predicate to filter the results. While technically ArticleQuery can also be used to look up content by its ID, we provide Article anyway for convenience since it is a common operation.

Much like in the Dari Java API Record#save, there is a single mutation field to handle both the create and update operations. You can use ArticleSave to create a new Article by omitting the id field from the input type ArticleInput. To update an existing Article, you must supply that Article’s ID along with any other fields you wish to update.

And finally, the ArticleDelete mutation field can be used to delete an Article by passing its ID as the argument.

Based on this schema, we can replicate the logic from the Java snippet above.