Within this tutorial, we will look at the new Content Delivery API that was released as part of Umbraco 12! The content delivery API is the first officially supported way for developers to build headless websites within the core Umbraco CMS product, so this is big news!

Within this article, I will assume that you have installed Umbraco 12 and that you want to build some sort of kick-ass headless site. Read on to not only learn how to enable the content delivery API in code, but how to best use it depending on if you're using SSR or SSG. To achieve this you will learn about the different endpoints, what they do, and when you should use each type. In essence, if you want to become an Umrbaco headless guru, read on 🔥🔥🔥

Content Delivery API Set-up

The first thing to point out when working with a new API is where you can find the official documentation. As you would expect from Umbraco, the API is well documented and that documentation can be found here. The other way to learn more about the new API endpoints is via Swagger. After you have your new site up and running with content delivery API enabled you can access the swagger documentation via this URL:

Out-of-the-box the content delivery API will not be enabled. You can enable the end-points within appsettings.json file. You will need to add a new section in UmbracoCMS, called DeliveryApi. Specifically, you will need to add a new section within UmbracoCMS, called DeliveryApi. That config should look like this:

You will also need to register some content delivery API-related dependencies. As we are using .NET 7 you would expect you can use the new minimal hosting model syntax in Program.cs with Umrbaco. Sadly, by default, this new way of removing Start.cs didn't natively support it. You can hack at it to get it working, however, you may face issues. Assuming that you still want to go ahead and just use a Program.cs (no Start.cs) you would register the content delivery API bits kind of like this:

The critical bit to this config above is the line that adds a call to AddDeliveryApi(). This is the line that registers the dependencies required by the API to function.

Another thing to point out about that config is that it follows the new minimal hosting model. Even though Umbraco runs on .NET 7, v12 does not fully support this new syntax. You can read more about the incompatibility issue here. For this reason, you might be better off still using a Startup.cs until minimal hosting is officially supported. The key bit of this config is the call to AddDeliveryApi().

After enabling Content Delivery API, you should also clear and regenerate your frontend content caches. You can do this within the Umbraco backend from this page:

SettingsExamine ManagementDeliveryApiContentIndexRebuild Index

After performing all these tasks, the content delivery API will be enabled and you will be ready to rock n roll!

Umbraco Content Delivery API Deep-Dive

Next, we will look at the three endpoints that the content delivery API exposes. The first one is a classic which is called content. This end-point can be used to return all the content that has been created within the CMS in one API call:

One issue with using this end-point is that it can potentially return a lot of content. This is why when you need to use it you will likely want to filter what data gets returned. One way to do this is to add pagination commands to the request. You can do this by supplying the take and skip commands as additional parameters, like this:

Skip and take both work like any other pagination operators, skip is used to get the current page number, and take is used to determine the number of results that will be returned per page.

The other reason why you might want to use this end-point is if you are using SSG (static-site generation) in order to build your webpages. When using SSG you will need to convert your CMS pages to static pages at build time.

Typically to do this you will need to create some templates in your website that make use of dynamic routing. Each page template will need to contain some code within functions like `getStaticPath. In this function, you will need to make a call to get all the URLs for the document type it represents.

For each page URL returned, you will need to define an additional query in a function like getStaticProps that gets all the data related to that page. For example, you might create a template in your website called blog that will be used to render all of the blog pages created inside the CMS. To get all the URLs that need to be rendered you will need to call the content end-point and use the filter parameter to filter the results by your blog document type and then use the returned segment property to then call Umbraco again to get the data related to that particular page.

When getting data, one issue that you might bump into is related data. What happens when you have a page that links to another page? A classic example of where this might happen is navigation. Imagine that when you did your content modeling, you defined a menu document type. This document type will likely contain properties that are used to link to other document types

To ensure the API is performant, the Umbraco team decided not to return any of the data contained within a relation like this by default. This also prevents cyclic references from accidentally occurring as well!

The good news is that if you want to return this additional data, you can. You can change the default behavior by supplying a property called expand. By supplying expand and specifying the property you want to expand, you can get additional data returned assuming that it exists. You can add the expand command like this:

Another issue with an API that returns everything is the potential that you accidentally return private data that was created using a document type that a content editor assumed would never be exposed publicly. Typically these types of document types will be used to model settings. Settings will typically contain sensitive data that should not be exposed outside of the CMS. If your system contains document types like this, what can you do to secure the content delivery API?

This is why on most projects, you will likely want to black-list certain document types from being returned via the API. Handily, Umbraco has your back here. You can restrict what document types can be exposed by content delivery API within our good old friend appsettings.config. To do this you can add a key DisallowedContentTypeAliases within the DeliveryApi section. An example of how to set this up is shown below:

Get data about a particular Item*: Getting all items is great, however, if you are using SSR in most instances you will likely need to query the CMS to get data about a particular page. This is where the item API comes into the mix. You can use the item API in one of two ways. First, you can get page data by supplying the page ID to the item end-point like this:

In reality, when you build your headless site, you will not know the page ID when a request is made in the front end. When someone is trying to access a page you will know the URL and nothing else. Usually, the only data you will have available within your website that you can use to query Umbraco will be the page Url. By supplying the page segment to the item API you can also get data about the related page back. Using the API in this mode is done like this:

Umbraco API Security

In terms of site security, you will likely not want any Tom, Dick, or Harry accessing your API. This is why you need to LOCK it down. This is done by defining an API key in config and by setting the API to be private using the PublicAccess setting. After enabling these two things in configuration, you will then need to supply the API key as an HTTP header value called api-key whenever you make a request to the API. Setting up an API key is done within appsettings.json like this:

The other benefit of adding an API key is that you can also use it to access preview and draft content. This is really important to allow content editors to preview changes on your site. In order to make the API return preview content instead of normal published content you need to enable preview mode. You can do this by supplying a parameter called preview as a host header to the request and setting it to true. To switch between preview content and normal content you will need to create an env var in your head that can be used to google this parameter on or off as needed!


These are the main things that you need to know in order to build a headless website with Umbraco using either server-side rendering or static-site generation. In the future, we will look at how to use this new knowledge to build a headless website using NextJs. Happy Coding 🤘