Content Management API

Content Management API #

Introduction #

Hi {{auth.user.firstName}}!

The Content Management API is a REST API for managing content.

The Content Management API is served at api.contentful.com.

In Contentful content is represented as Entries and Assets divided into Spaces. Apps and websites depend on the structure of Entries, so every Entry must comply to a specific Content Type. Assets represent binary files like images, videos and other media.

Entries are represented as JSON data; Assets are represented as (binary) files.

The API can be securely accessed via HTTPS and will only be available to clients authenticating with an access token.

Managing content via an API has many benefits:

  • Custom applications can use the API to manage content.
  • Scripts can use the API to automate various tasks.
  • Contentful's own content management web app is a user-friendly JavaScript application which is solely based on the API.

If you want to deliver content (e.g. to the web or to mobile apps) use the Content Delivery API. The Content Management API is meant to be used only for managing content, not delivering it. For example, you shouldn't use the Content Management API to display blog posts on a web site or pull information into a mobile web app unless that app is meant for editing content.

We've made this documentation very interactive. To get started just read further and we'll take you through a quick tour of the Content Management API.

Getting Started #

In order to use the Content Management API you need an OAuth access token to authenticate with the API. To easily get you an access token we've made this documentation an interactive OAuth application.

If you have a Contentful account you can authorize this app to access your data. After the login, URIs and code snippets within this document are customized to use your credentials.

Something went wrong during login. Here are the scary details:

{{auth.message}}

If you think something is wrong, please get in touch and include the details above!

Logged in as {{auth.user.firstName}}. Here's your OAuth access token:

{{auth.accessToken}}

URIs and code snippets within this document have been updated to use your credentials.

Open up Contentful's UI and see the effects of your API requests!

This access token should only be used for learning and testing purposes. Please create a separate OAuth application for production usage.

What's next #

In the following sections you'll learn about a few high-level concepts. We'll go through using all endpoints and you'll learn how they work in detail.

You are encouraged to follow along in your Terminal. Most topics have example snippets that you can copy, paste and execute to inspect the results. Of course, nothing prevents you from using the API with languages other than JavaScript.

We hope you enjoy the interactive way of learning about the API.

Authentication #

Getting an Access Token #

To get an access token you need a Contentful account.

Using the Access Token #

To manage content with the Content Management API, clients need to provide an access token. Access tokens are attached to a user and used by clients to access Spaces the user has access to.

The Content Management API implements the standardized OAuth 2.0 Bearer Token Specification. This authorization scheme is very simple and already supported by many HTTP clients.

The API supports two mechanisms for supplying the access token.

As an Authorization HTTP request-header field:

curl -X GET https://api.contentful.com/spaces \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

As an URI query parameter named access_token:

curl -X GET https://api.contentful.com/spaces?access_token={{auth.accessToken || "ACCESS_TOKEN"}} \
     -H 'Content-Type: application/vnd.contentful.management.v1+json'

When searching for Entries and Content Types you can customize the search query in many ways.

Content Type #

Search for Entries with a specific Content Type by setting the content_type URI query parameter to the ID of the Content Type you want to search for.

When querying Entries and using search filters based on fields or ordering by fields you must specify this parameter.

Let's find all Entries of Content Type "cat":

client.entries({
  'content_type': 'cat'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?content_type=cat&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"content_type": @"cat" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('content_type' => 'cat')

Filters #

Search filters allow you to filter by resources' fields in powerful ways:

Note that if you're searching Entries and filtering or ordering by fields you must specify the content_type parameter. See range filtering for an example of this. If you're filtering or ordering by sys you don't need to specify the parameter.

Equality & Inequality #

Search for exact matches by using the equality operator.

Let's find all Entries with ID nyancat (hint: IDs are unique and there can only be one):

client.entries({
  'sys.id': 'nyancat'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?sys.id=nyancat&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"sys.id": @"nyancat" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];

A reason to query an Entry by ID like above instead of retrieving the Entry itself might be because you want to include resolved links.

The inequality operator can be used to look for fields that don't match a specific value.

For example, here's how to get all Entries except nyancat:

client.entries({
  'sys.id[ne]': 'nyancat'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?sys.id[ne]=nyancat&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"sys.id[ne]": @"nyancat" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('sys.id[ne]' => 'nyancat')

The equality/inequality operators also works with Array fields: If one of the items in an Array field matches the value the field will match.

Let's find all cats who like lasagna by matching fields.likes (Array) against a single value:

client.entries({
  'content_type': 'cat',
  'fields.likes': 'lasagna'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?content_type=cat&fields.likes=lasagna&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"content_type": @"cat",
                              @"fields.likes": @"lasagna" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('content_type' => 'cat', 'fields.likes' => 'lasagna')

Inclusion & Exclusion #

Filter a field by multiple values via the in operator.

When applied to an array value there must be at least one matching item.

Let's get Entries for finn and jake:

client.entries({
  'sys.id[in]': ['finn', 'jake']
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?sys.id[in]=finn,jake&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"sys.id[in]": @[ @"finn", @"jake" ] }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('sys.id[in]' => 'finn,jake')

Let's get all cats that like neither rainbows nor lasagna:

client.entries({
  'content_type': 'cat',
  'fields.likes[nin]': ['rainbows', 'lasagna']
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?content_type=cat&fields.likes[nin]=rainbows,lasagna&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"content_type": @"cat",
                                @"fields.likes[nin]": @[ @"rainbows", @"lasagna" ] }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('sys.id[nin]' => 'rainbow,lasagna')

Number & Date Ranges #

Four range operators are available:

  • lt: Less than
  • lte: Less than or equal to
  • gt: Greater than
  • gte: Greater than or equal to

Those operators can be applied to Date, Integer and Number Fields.

Let's find all cats which have 3 or less lives left:

client.entries({
  'content_type': 'cat',
  'fields.lives[lte]': 3
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?content_type=cat&fields.lives[lte]=3&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"content_type": @"cat",
                                @"fields.lives[lte]": @(3) }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('content_type' => 'cat', 'fields.lives[lte]' => '3')

These cats should be more careful!

We can also filter by date ranges.

Let's look for Entries that've been updated since midnight of January 1st 2013:

client.entries({
  'sys.updatedAt[gte]': '2013-01-01T00:00:00Z'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?sys.updatedAt[gte]=2013-01-01T00:00:00Z&access_token=b4c0n73n7fu1


NSDate* date = [[ISO8601DateFormatter new] dateFromString:@"2013-01-01T00:00:00Z"];

[client fetchEntriesMatching:@{ @"sys.updatedAt[gte]": date }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries 'sys.updatedAt[gte]' => DateTime.parse('2013-01-02T00:00:00Z')
# or
client.entries 'sys.updatedAt[gte]' => '2013-01-02T00:00:00Z'

Full-text Search #

Full-text search across all Text Fields via query querystring parameter.

Let's find all Entries matching "bacon":

client.entries({query: 'bacon'}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?query=bacon&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"query": @"bacon" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('query' => 'bacon')

Full-text Search on a specific field via match operator.

Let's find all things with "bacon pancakes" in their description:

client.entries({
  'content_type': 'dog',
  'fields.description[match]': 'bacon pancakes'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?content_type=dog&fields.description\[match\]=bacon&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"content_type": @"dog",
                                @"fields.description[match]": @"bacon pancakes" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('content_type'=> 'dog', 'fields.description[match]' => 'bacon pancakes')

Location-based search #

Contentful works great with location-enabled content:

  • Let users find places closest to where they currently are
  • Show places within a specific map area
  • Find places in the vicinity of another place

Entries can have location fields. For example, imagine a Restaurant Entry with a field called location indicating where the Restaurant is located. Once you've added location information to your content you can benefit from all of the above features simply by using the search in a specific way:

Restaurants "near me"

A common use case for location search is to search for places close to the user's current position.

Use the near operator to show results closest to a specific map location and order the results by distance.

fields.location[near]=23,42&content_type=restaurant

This will return all entries sorted by distance from the point at latitude=23 and a longitude=42.

Search within bounding rectangle

When you're displaying content on a map it makes sense to retrieve only content that is visible on the currently visible map rectangle.

For this case, use the within operator with the following value:

fields.location[within]=1,2,3,4&content_type=restaurant

This will return entries where fields.location is within the rectangle with:

  • Bottom left corner: latitude 1, longitude 2
  • Top right corner: latitude 3, longitude 4
Search within bounding circle

Similar to the "near me" use case, this lets you search for locations that are within a specific circle on the map. This can be useful for finding related Entries that are in the vicinity of another Entry.

fields.location[within]=1,2,3&content_type=restaurant

This will return Entries where fields.location is inside of the circle with latitude=1, longitude=2 and a radius of 3 kilometers.

Order #

Order items by specifying the order search parameter.

Let's get all Content Types ordered by their creation date:

client.entries({
  order: 'sys.createdAt'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?order=sys.createdAt&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"order": @"sys.createdAt" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('order' => 'sys.createdAt')

Reverse the sort-order by prefixing the field with a minus-sign.

For example, order by time of last update starting with the newest Entries.

client.entries({
  order: '-sys.updatedAt'
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?order=-sys.updatedAt&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"order": @"-sys.updatedAt" }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('order' => '-sys.createdAt')

Note that when ordering Entries by fields you must set the content_type URI query parameter to the ID of the Content Type you want to filter by.

Limit & Skip #

Specify the maximum number of results as limit search parameter:

Example: Limit to 3 Entries

client.entries({limit: 3}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?limit=3&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"limit": @3 }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('limit' =>'1')

Specify an offset as the skip search parameter:

Example: Skip 3 Entries

client.entries({skip: 3}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?skip=3&access_token=b4c0n73n7fu1

[client fetchEntriesMatching:@{ @"skip": @3 }
                     success:^(CDAResponse *response, CDAArray *array) {
                         NSLog(@"%@", array);
                     } failure:^(CDAResponse *response, NSError *error) {
                         NSLog(@"%@", error);
                     }];
client.entries('skip' =>'3')

By combining skip and limit you can achieve pagination:

  • Page 1: skip=0, limit=15
  • Page 2: skip=15, limit=15
  • Page 3: skip=30, limit=15
  • etc.

Links are a very powerful way to model relationships between pieces of content. Contentful's search is built to make linked data retrieval as simple as adding an additional URI query parameter to retrieve an entire web of related content that you can display in your application.

Basically Resources can have Link fields which point to other Entries or Assets.

When you have related content (e.g. Entries with links to other Entries) it's possible include both search results and related data in a single request.

Simply tell the search to include the targets of links in the response: Set the include parameter to the number of levels you want to resolve. The maximum number of inclusion is 10.

To illustrate this, note that the cat Content Type has a Link field that links to the cat's best friend.

Let's serach for the nyancat Entry and include 1 level of linked Entries:

client.entries({
  'sys.id': 'nyancat',
  'include': 1
}).then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/entries?sys.id=nyancat&include=1&access_token=b4c0n73n7fu1
 [client fetchEntriesMatching:@{ @"sys.id": @"nyancat", @"include": @(1) }
                       success:^(CDAResponse *response, CDAArray *array) {
                           NSLog(@"%@", array);
                       } failure:^(CDAResponse *response, NSError *error) {
                           NSLog(@"%@", error);
                       }];
client.entries('sys.id' => 'nyancat', include: 1)

The search result will include the requested Entry matching the query in items along with the linked Entries and Assets in includes.

Link resolution works regardless of how many results are there in items. Some examples for this are:

  • Get a list of blog posts in items with related authors, categories and other meta data in includes.
  • Get a single restaurant in items along with its menu, menu items and photos (Assets) in includes.

Important note: If an item is already present in the response's items, it will not be included in the include.Entry again!

The JS library resolves links automatically: If you query with include links will be replaced with references to the actual objects.

JSON Format Details #

Resources are represented as JSON.

Date & Time Format #

Dates and times are an important part of all content. Let's look at an Entry:

{
  "sys": {
    "type": "Entry",
    "id": "nyancat",
    "createdAt": "2013-05-01T08:00:00Z",
    "updatedAt": "2013-05-02T13:00:00Z"
  }
}

Here we can see a few dates and times in both the content and the system properties:

  • Nyan Cat's birthday is April 2nd 2011
  • Nyan Cat's meal time is 13:00
  • The nyancat entry has been created May 1st 2013 at 08:00
  • The nyancat entry has been updated May 2nd 2013 at 13:00

In JSON date and time are always represented as ISO 8601-encoded string.

System-generated dates are represented as UTC.

Localization #

Assets and Entries can be localized: Each field in an Asset or an Entry can exist in multiple locales.

Let's look at this excerpt of a localized Blog Post Entry for example:

{
  "fields": {
    "title": {
      "en-US": "Nyan cat has been spotted in the wild!",
      "tlh": "chaDo'maq nyan vIghro' qaStaHvIS qu'bogh!"
    }
  }
}

In the Content Delivery API fields of Entries and Assets will be flattened to the value of the requested or the default locale.

Links represent relationships between Resources, for example:

  • A restaurant linking to its menu (singular relationship)
  • A menu linking to its specific menu items (plural relationship)
  • Each menu item linking to a photo (attachment)
  • A restaurant linking to multiple photos (multiple attachments)

When using links to model relationships between Entries and model attachments you benefit from many great features:

  • Relationships are clearly defined and validated by special Content Type Fields
  • Entry Links can be validated by Content Type. E.g.: Only allow Menu Items for fields.menuItems.
  • Asset Links can be validated by File Type. E.g.: Only allow Images for fields.photo.
  • The Content Delivery API is highly optimized for Links: A single HTTP request let's you retrieve an entire web of linked Resources: A restaurant with its menu, all menu items and all of their attachments - everything in the example above. A mobile app could immediately display something, if not everything, after a single request. This is very important for mobile apps where latency is a big issue: Instead of doing hundreds of requests, do a single request which can also be cached by Contentful's CDN to speed up future requests even more. Learn how to resolve a web of Links in the Content Delivery API.

Linking an Entry to another Entry represents a relationship.

For example, here's a restaurant pointing to its menu:

{
  "sys": {
    "type": "Entry",
    "id": "il-doges"
  },
  "fields": {
    "menu": {
      "en-US": {
        "sys": {
          "type": "Link",
          "linkType": "Entry",
          "id": "il-doges-nice-menu"
        }
      }
    }
  }
}

il-doges' fields.menu links to il-doges-nice-menu.

It's possible to create circular links: You could model a circular chain of Entries to model a dialog in a video game or more complex graphs. There are many possibilities, it's up to you to decide!

Various fields in every Resource's sys are also Links: The Space they're in, their Content Type (in case of Entries) or Users who created or modified them.

Of course, an Entry can also link to more than one Entry or Asset:

  • Have multiple Link Fields, e.g. fields.menu and fields.openingHours in the restaurant. These represent semantically different Links because of the name & type of the Field they're stored in. You can even limit the Entries a Link Field may point to by specifying a Link Content Type Validation on the Field.
  • Have an Array of Links Field, e.g. fields.menuItems in the restaurant's menu. This represents an (orderable) list of related items. Often you may want to model nothing but an ordered list: In this case, simply create a Content Type with a single Field that links to Entries.

Entries linking to Assets represent attachments.

For example, here's a restaurant pointing to some photos:

{
  "sys": {
    "type": "Entry",
    "id": "il-doges"
  },
  "fields": {
    "mainPhoto": {"en-US":
      {"sys": {"type": "Link", "linkType": "Asset", "id": "such-doge"}
    },
    "photos": {"en-US": [
      {"sys": {"type": "Link", "linkType": "Asset", "id": "nice-food"}},
      {"sys": {"type": "Link", "linkType": "Asset", "id": "such-doge"}},
      {"sys": {"type": "Link", "linkType": "Asset", "id": "wow"}}
    ]}
  }
}

il-doges' fields.mainPhoto links to such-doge, fields.photos link to more photos, including the mainPhoto.

Just as with Entry links you can have multiple Fields linking to a single (fields.mainPhoto) or multiple (fields.photos) Assets.

You can limit the type of Asset a Link Field can link to by specifying an Asset File Type Validation on the Field.

Adding Links to an Entry requires the Entry's Content Type to have one or more Link Fields.

Let's look at some example Field values. Remember that these need to be used in context of a Content Type like this:

{
  "sys": {"type": "ContentType", "id": "restaurant"},
  "fields": [
    ...
  ]
}

Link Field for Entry #

{
  "id": "menu",
  "type": "Link",
  "linkType": "Entry"
}
{
  "id": "menuItems",
  "type": "Array",
  "items": {
    "type": "Link",
    "linkType": "Entry"
  }
}
{
  "id": "mainPhoto",
  "type": "Link",
  "linkType": "Asset"
}
{
  "id": "photos",
  "type": "Array",
  "items": {
    "type": "Link",
    "linkType": "Asset"
  }
}

Link values are used in Entries to specify actual Links to other Entries or Assets. Before you can add those links you need to have added Link Fields to a Content Type.

Link values are represented as objects containing a sys property with the type and ID of the resource they're linking to:

Field Type Description
sys.type String Always "Link".
sys.linkType String Type of linked Resource.
sys.id String ID of linked Resource.

Let's look at some example Link values. Remember that these need to be used in context of an Entry like this:

{
  "sys": {"type": "Entry", "id": "restaurant"},
  "fields": {
    "someField": {
      "en-US": ...
    }
  }
}

Link to an Entry #

{
  "sys": {
    "type": "Link",
    "linkType": "Entry",
    "id": "il-doges-nice-menu"
  }
}
[
  {"sys": {"type": "Link", "linkType": "Entry", "id": "nice-burger"}},
  {"sys": {"type": "Link", "linkType": "Entry", "id": "such-dessert"}},
  {"sys": {"type": "Link", "linkType": "Entry", "id": "WOW"}}
]
{
  "sys": {
    "type": "Link",
    "linkType": "Asset",
    "id": "such-doge"
  }
}
[
  {"sys": {"type": "Link", "linkType": "Entry", "id": "nice-food"}},
  {"sys": {"type": "Link", "linkType": "Entry", "id": "such-doge"}},
  {"sys": {"type": "Link", "linkType": "Entry", "id": "wow"}}
]

API Versioning #

All API requests should specify a Content-Type header of application/vnd.contentful.management.v1+json.

Otherwise, we will automatically route your request to the latest version of the API. This could break clients which expect the outdated API version. To be on the safe side, always specify the Content-Type header.

Webhooks #

Webhooks in Contentful can notify you or someone else when content has changed. For example, when an Entry has been published Contentful sends the published Entry to a preconfigured HTTP endpoint. This can be used for notifications, static site generators or other forms of post-processing that is sourced from Contentful.

Webhooks are called when Assets, Entries or Content Types are published or unpublished. Therefore the Webhook's receiver will always get the latest version (or deletion thereof) available through the Delivery API.

You can create and manipulate Webhook Definitions using the Management API.

To see how an actual Webhook HTTP request looks like please refer to the Delivery API's Webhook section.

Creating a Webhook #

Create a Webhook without an ID:

curl -X POST https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"url":"https://www.example.com"}'

Or create a Webhook with a specific ID:

curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions/foobar \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"url":"https://www.example.com"}'

Listing Webhooks #

List all Webhooks:

curl -X GET https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Getting a Webhook #

Getting Webhook with the ID foobar:

curl -X GET https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions/foobar \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Updating a Webhook #

Updating Webhook with the ID foobar:

curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions/foobar \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 1' \
     -d '{"url":"https://example.com/v2"}'

Deleting a Webhook #

Deleting Webhook with the ID foobar:

curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/webhook_definitions/foobar \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Webhook Fields #

Field Type Description
sys Sys See common system properties.
url String URL of Webhook receiver where HTTP request will be made.
httpBasicUsername String (Optional) HTTP Basic auth username
httpBasicPassword String (Optional) HTTP Basic auth password

HTTP Details #

Security #

The Content Management API is fully available via SSL: Both JSON data and Assets should be requested through a secure transport.

Using SSL ensures that the entire content and access tokens of a Space remain secure and can not be intercepted by potential eavesdroppers.

Unless there is a reason to disable SSL you should leave it enabled to ensure maximum privacy for clients.

Cross-origin resource sharing #

CORS (Cross-origin resource sharing) allows JavaScript web apps to make HTTP requests to other domains. This is very important for third party web apps using Contentful: Without CORS, a JS app on https://example.com couldn't access the Content Management or the Content Delivery API because they're on contentful.com which is a different domain. In short, without CORS it wouldn't be possible to easily access Contentful's APIs from a third party web app.

To allow JavaScript applications running inside browsers to freely interact with our APIs we're setting the following HTTP response headers:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Headers: A long list of common headers
  • Access-Control-Allow-Methods: Common HTTP verbs
  • Access-Control-Max-Age: Reasonably high to avoid preflight requests

This should allow web apps to do whatever the user has given them permission for.

Note: Allowing all origins is safe because of the way the APIs are designed:

  • All requests must include an access token in the query string or as header for every request. They will never be sent implicitly by a cookie.
  • Destructive requests can only be issued against the HTTPS endpoint.

CORS is supported by all modern browsers. Read how to use CORS in this HTML5 rocks tutorial on CORS.

Encoding #

JSON is encoded in UTF-8.

GZip Compression #

All API endpoints support GZip compression to save valuable bandwidth. Please take into account that enabling compression will also put more load on your clients' processors.

Libraries #

We have created some libraries to simplify integrating Contentful with various programming languages. If there's no integration for your language yet you can still talk to the HTTP endpoints directly. We are working on integrations for other languages.

JavaScript #

Objective-C #

Other #

We are working on integrations for Ruby and Android.

Getting Help #

Resources #

There are many types of things which we call Resources: Spaces, Content Types, Entries, Assets, etc. Regardless of which type of Resource you are interacting with, there are some rules that apply to all of them. For example, when updating the name of a Space you need to specify its previous version just as when updating fields inside an Entry.

System Properties #

All resources have a root-level property called sys. It contains system-related meta information:

Field Type Description
sys.type String Type of resource.
sys.id String Unique ID of resource.
sys.space Link Link to resource's Space (except Spaces) .
sys.contentType Link Link to Entry's Content Type (Entries only).
sys.version Integer Version of resource.
sys.createdAt Date Time entity was created.
sys.updatedAt Date Time entity was updated.

Resource URLs #

The API follows REST principles and therefore provides Spaces, Entries and other entities as resources. All resources have descriptive URLs that speak for themselves.

For example, the Space with the ID "cfexampleapi" has this URI:

https://api.contentful.com/spaces/cfexampleapi

And within this Space, an Entry with the ID "nyancat" has this URI:

https://api.contentful.com/spaces/cfexampleapi/entries/nyancat

You'll be seeing these and other URIs in HTTP snippets throught this document.

Resource IDs #

When creating a resource you may either chose an ID or let the server generate a random ID for you.

When choosing an ID yourself it must adhere to the following rules:

  • Length must be between 1 and 64 characters
  • May consist of alphanumeric characters, minus "-", underscore "_" and period "."

In terms of a regular expression: /^[a-zA-Z0-9-_.]{1,64}$/.

Note that you can not choose an ID when creating a Space. For Spaces you may only use the POST method and let the server generate a random ID for you.

Choose an ID by doing a PUT request to the resource's URI:

space.createEntry('blog-post', {
  sys: {id: 'bar'},
  ...
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/SPACE/entries/bar \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'X-Contentful-Content-Type: baz' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"fields":{"name":{"en-US":"bar"}}}'

Let the server generate a random ID by doing a POST request to the appropriate endpoint:

space.createEntry('blog-post', {
  ...
}).then(log.ok, log.fail);
curl -X POST https://api.contentful.com/spaces/SPACE/entries \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'X-Contentful-Content-Type: baz' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"fields":{"name":{"en-US":"bar"}}}'

Note that resource IDs are unique within their respective Space and their type:

For example, you could have two Spaces which both have an Entry with ID = "foobar". But you could not have two Entries with ID = "foobar" within the same Space.

Resource IDs are also unique per type: While the example before explained you can't have two Entries with the same ID, you could have an Entry with ID = "foobar" and a Content Type with ID = "foobar".

Updating Resources #

When updating an existing resource don't only pass the changes you made; Instead pass the entire resource including the changes you've made. In other words: Do not pass a subset of properties and expect some kind of merge to occur. If you update with only a subset of properties all existing properties which are not part of that update will be gone.

To summarize, resources should always be updated like this:

  • Fetch current resource
  • Make changes to current resource
  • Update resource by passing changed resource along with current version number

This way no unseen changes are ever overridden and unexpected conflicts are unlikely to occur.

Updating & Version Locking #

Contentful uses optimistic locking. When updating an existing resource its previous version needs to be specified. The version is compared with the resource's current version on the server to ensure that a client doesn't overwrite a resource that has since been updated. If the version changed in between the update will be rejected.

Pass the previous version as the `X-Contentful-Version` header:
curl -X PUT https://api.contentful.com/spaces/SPACE \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 23' \
     -d '{"name":"Hyper Space"}'

Publishing #

Publishing a Content Type or an Entry makes it available to the Content Delivery API.

When publishing you need to send along the current version number, just like when updating the resource itself.

Spaces #

Spaces are containers for Content Types, Entries and Assets and other resources. API consumers, like mobile apps or websites, typically fetch data by getting Entries and Assets from one or more Spaces.

Creating a Space #

Create a new Space by doing a POST request to the /spaces endpoint:

client.createSpace({name: 'Example Space'}).then(log.ok, log.fail);
curl -X POST https://api.contentful.com/spaces \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"name":"Example Space"}'

Response
{
  "sys": {
    "type": "Space",
    "id": "1vlwe1hnkhmk",
    "version": 0,
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "createdAt": "2013-09-22T17:34:53Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "updatedAt": "2013-09-22T17:34:53Z"
  },
  "name": "Example Space"
}

Creating a Space in a specific Organization #

In Contentful you can be a member of multiple Organizations.

Depending on your role in the organization you can create Spaces in them or not: Only organization owners and admins have this permission.

When you sign up the first time, you'll create a new organization. When you're invited to an existing organization, you'll become a member of it.

If you only have a single organization, any Space you create will be automatically associated with that organization.

However, if you're an admin or an owner in multiple organizations you need to pass the ID of the organization you want to create the Space in.

For example, let's say you're a member of two organizations:

  • Bacon Corp (id="bacon")
  • Tofu Enterprises (id="tofu")

And now we intend to create a Space called "Vegan Guide" in the appropriate organization:

client.createSpace({name: 'Vegan Guide'}, 'tofu').then(log.ok, log.fail);
curl -X POST https://api.contentful.com/spaces \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'X-Contentful-Organization: tofu' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"name":"Example Space"}'

Listing Spaces #

List all Spaces by doing a GET request to the /spaces endpoint:

client.getSpaces().then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "sys": {
    "type": "Array"
  },
  "items": [
    {
      "sys": {
        "type": "Space",
        "id": "1vlwe1hnkhmk",
        "version": 0,
        "createdBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        },
        "createdAt": "2013-09-22T17:34:53Z",
        "updatedBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        },
        "updatedAt": "2013-09-22T17:34:53Z"
      },
      "name": "Example Space"
    }
  ],
  "total": 1,
  "limit": 25,
  "skip": 0
}

Getting a Space #

Get a Space by doing a GET request to /spaces/ID:

client.getSpace('1vlwe1hnkhmk').then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/1vlwe1hnkhmk \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "sys": {
    "type": "Space",
    "id": "1vlwe1hnkhmk",
    "version": 0,
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "createdAt": "2013-09-22T17:34:53Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "updatedAt": "2013-09-22T17:34:53Z"
  },
  "name": "Example Space"
}

Updating a Space #

Update an existing Space by doing a PUT request to /spaces/ID:

client.getSpace('1vlwe1hnkhmk').then(function(space) {
  space.name = 'Outer Space';
  return client.updateSpace(space);
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/1vlwe1hnkhmk \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 0' \
     -d '{"name":"Outer Space"}'

Response
{
  "sys": {
    "type": "Space",
    "id": "1vlwe1hnkhmk",
    "version": 1,
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "createdAt": "2013-09-22T17:34:53Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "updatedAt": "2013-09-22T17:41:45Z"
  },
  "name": "Outer Space"
}

Deleting a Space #

Delete an existing Space by doing a DELETE request to /spaces/ID. Note that deleting a Space will remove its entire content, including all Content Types, Entries and Assets. Be careful as this action can not be undone.

client.getSpace('1vlwe1hnkhmk').then(function(space) {
  return client.deleteSpace(space);
}).then(log.ok, log.fail);

// or delete Space by ID:
client.deleteSpace('1vlwe1hnkhmk').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/1vlwe1hnkhmk \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response

Empty response.

Space Fields #

Field Type Description
sys Sys See common system properties.
name String Name of the Space.
locales [Locale] List of Locales.

A Locale is a language in which content is available in within one specific Space. See Localization.

Field Type Description Example
code String Code of the Locale. "en-US"
name String Name of the Locale. "English"

Content Types #

Content Types are schemas describing the shape of Entries. They mainly consist of a list of fields acting as a blueprint for Entries.

For example, let's say we want to publish blog post articles. First thing we have to do is define a Content Type which describes those blog posts. A simple Content Type with title and body fields would look like this (sys left out intentionally):

{
  "name": "Blog Post",
  "fields": [
    {  
      "id": "title",
      "name": "Title",
      "type": "Text",
      "required": true,
      "localized": true
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text",
      "required": true,
      "localized": true
    }
  ]
}

Entries for this Content Type must have a title and a text field because of required: true. Also localized: true tells us that both fields can be localized. See below for an Entry that fits this Content type.

Note: Content Types are not related to the HTTP Content-Type header.

Creating a Content Type #

Let's create a Content Type for blog posts. Blog posts will have a title and a body field. The Content Type should have an ID of "blog-post". To choose an ID issue a PUT request to the resource's URI:

space.createContentType({
  sys: {id: 'blog-post'},
  name: 'Blog Post',
  fields: [
    {id: 'title', name: 'Title', type: 'Text'},
    {id: 'body', name: 'Body', type: 'Text'}
  ]
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"name":"Blog Post","fields":[{"id":"title","name":"Title","type":"Text"},{"id":"body","name":"Body","type":"Text"}]}'

Response
{
  "name": "Blog Post",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Text"
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text"
    }
  ],
  "sys": {
    "id": "blog-post",
    "type": "ContentType",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T21:42:00.184Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T21:42:00.184Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Listing Content Types #

List Content Types in a space.

space.getContentTypes().then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/content_types \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "sys": {
    "type": "Array"
  },
  "total": 1,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "name": "Blog Post",
      "fields": [
        {
          "id": "title",
          "name": "Title",
          "type": "Text"
        },
        {
          "id": "body",
          "name": "Body",
          "type": "Text"
        }
      ],
      "sys": {
        "id": "blog-post",
        "type": "ContentType",
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "7daovfk1olns"
          }
        },
        "createdAt": "2013-09-22T21:42:00.184Z",
        "createdBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        },
        "version": 1,
        "updatedAt": "2013-09-22T21:42:00.187Z",
        "updatedBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        }
      }
    }
  ]
}

Getting a Content Type #

Get a Content Type with the ID "blog-post".

space.getContentType('blog-post').then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "name": "Blog Post",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Text"
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text"
    }
  ],
  "sys": {
    "id": "blog-post",
    "type": "ContentType",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T21:42:00.184Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T21:42:00.187Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Updating a Content Type #

Update the Content Type for a blog post by adding a description:

space.getContentType('blog-post').then(function(contentType) {
  contentType.description = 'Simple blog post with title and body fields.';
  return space.updateContentType(contentType);
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 1' \
     -d '{"name":"Blog Post","description":"Simple blog post with title and body fields.","fields":[{"id":"title","name":"Title","type":"Text"},{"id":"body","name":"Body","type":"Text"}]}'

Response
{
  "name": "Blog Post",
  "description": "Simple blog post with title and body fields.",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Text"
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text"
    }
  ],
  "sys": {
    "id": "blog-post",
    "type": "ContentType",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T21:42:00.184Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 2,
    "updatedAt": "2013-09-22T21:49:43.396Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Activating a Content Type #

Before you can create Entries of a certan Content Type you need to activate it.

Activate a Content type with the ID "blog-post".

space.getContentType('blog-post').then(function(contentType) {
  return space.publishContentType(contentType);
}).then(log.ok, log.fail);

// or activate Content Type by ID & version:
space.publishContentType('blog-post', 1).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 2' \
     -H 'Content-Length: 0'

Response
{
  "name": "Blog Post",
  "description": "Simple blog post with title and body fields.",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Text"
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text"
    }
  ],
  "sys": {
    "id": "blog-post",
    "type": "ContentType",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T21:42:00.184Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 3,
    "updatedAt": "2013-09-22T21:51:42.138Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T21:51:42.138Z",
    "publishedCounter": 1,
    "publishedAt": "2013-09-22T21:51:42.138Z",
    "publishedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "publishedVersion": 2
  }
}

Deactivating a Content Type #

Before you can deactivate a Content Type all Entries using that Content Type must be removed.

Deactivate a Content type with the ID "blog-post".

space.getContentType('blog-post').then(function(contentType) {
  return space.unpublishContentType(contentType);
}).then(log.ok, log.fail);

// or deactivate Content Type by ID:
space.unpublishContentType('blog-post').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "name": "Blog Post",
  "description": "Simple blog post with title and body fields.",
  "fields": [
    {
      "id": "title",
      "name": "Title",
      "type": "Text"
    },
    {
      "id": "body",
      "name": "Body",
      "type": "Text"
    }
  ],
  "sys": {
    "id": "blog-post",
    "type": "ContentType",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T21:42:00.184Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T21:51:42.138Z",
    "publishedCounter": 1,
    "version": 4,
    "updatedAt": "2013-09-22T21:55:11.920Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Deleting a Content Type #

Before you can delete a Content Type you need to deactivate it.

Delete a Content Type with the ID "blog-post".

space.getContentType('blog-post').then(function(contentType) {
  return space.deleteContentType(contentType);
}).then(log.ok, log.fail);

// or delete by ID:
space.deleteContentType('blog-post').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/content_types/blog-post \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response

Empty response.

Content Type Fields #

Field Type Description
sys Sys See common system properties.
name String Name of the Content Type.
description String Description of the Content Type.
fields [Field] List of Fields.
displayField String ID of main Field used for display.

A Field describes a single property of an Entry:

Field Type Description
id String ID of the Field.
name String Name of the Field.
type String Type of the Field.
items Schema (Array type only) Schema for items.
required Boolean Describes whether the Field is mandatory.
localized Boolean Describes whether the Field is localized.

Field types:

Name JSON Primitive Description
Symbol String Basic list of characters. Maximum length is 256.
Text String Same as Symbol, but can be filtered via Full-Text Search. Maximum length is 50,000.
Integer Number Number type without decimals. Values from -2^53 to 2^53.
Float Number Number type with decimals.
Date String See Date & Time Format.
Boolean Boolean Flag, true or false.
Link Object See Links
Array Array List of values. Value type depends on field.items.type.
Object Object Arbitrary Object.

Entries #

Entries represent textual content in a Space. An Entry's data adheres to a certain Content Type.

For example, let's look at an Entry that fits the Blog Post Content Type:

{
  "fields": {
    "title": {
      "en-US": "Hello, World!",
      "de-DE": "Hallo, Welt!"
    },
    "body": {
      "en-US": "Bacon is healthy!",
      "de-DE": "Bacon ist gesund!"
    }
  }
}

Creating an Entry #

Before you can create an Entry you need to create and activate a Content Type.

When creating a new Entry you need to pass the ID of the Entry's desired Content Type as the X-Contentful-Content-Type header.

Create a Blog Post Entry:

space.createEntry('blog-post', {
  sys: {id: 'hello-world'},
  fields: {
    title: {'en-US': 'Hello, World!'},
    body: {'en-US': 'Bacon is healthy!'}
  }
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Content-Type: blog-post' \
     -d '{"fields":{"title":{"en-US":"Hello, World!"},"body":{"en-US":"Bacon is healthy!"}}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Hello, World!"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T23:05:03.271Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Listing Entries #

Search Entries in a space.

 space.getEntries().then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/entries \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "sys": {
    "type": "Array"
  },
  "total": 1,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "fields": {
        "title": {
          "en-US": "Hello, World!"
        },
        "body": {
          "en-US": "Bacon is healthy!"
        }
      },
      "sys": {
        "id": "hello-world",
        "type": "Entry",
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "7daovfk1olns"
          }
        },
        "createdAt": "2013-09-22T23:05:03.271Z",
        "createdBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        },
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "blog-post"
          }
        },
        "version": 1,
        "updatedAt": "2013-09-22T23:05:03.275Z",
        "updatedBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        }
      }
    }
  ]
}

When querying Entries by fields you need to specify a Content Type by setting the content_type parameter to the ID of the Content Type you want to filter by.

See Search Parameters to learn how to search for specific things.

Getting an Entry #

Get the Entry with an ID of "hello-world".

space.getEntry('hello-world').then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Hello, World!"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T23:05:03.275Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Updating an Entry #

Update the Entry with an ID of "hello-world".

space.getEntry('hello-world').then(function(entry) {
  entry.fields.title['en-US'] = 'Crispy bacon news';
  return space.updateEntry(entry);
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 1' \
     -d '{"fields":{"title":{"en-US":"Crispy bacon news"},"body":{"en-US":"Bacon is healthy!"}}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Crispy bacon news"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 2,
    "updatedAt": "2013-09-22T23:26:04.733Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Publishing an Entry #

Publish the Entry with an ID of "hello-world".

space.getEntry('hello-world').then(function(entry) {
  return space.publishEntry(entry);
}).then(log.ok, log.fail);

// or publish Entry by ID & version:
space.publishEntry('hello-world', 1).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 2' \
     -H 'Content-Length: 0'

Response
{
  "fields": {
    "title": {
      "en-US": "Crispy bacon news"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 3,
    "updatedAt": "2013-09-22T23:28:11.503Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T23:28:11.503Z",
    "publishedCounter": 1,
    "publishedAt": "2013-09-22T23:28:11.503Z",
    "publishedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "publishedVersion": 2
  }
}

After publishing the Entry it will be available via the Content Delivery API.

Unpublishing an Entry #

Unpublish the Entry with the ID "hello-world".

space.getEntry('hello-world').then(function(entry) {
  return space.unpublishEntry(entry);
}).then(log.ok, log.fail);

// or unpublish Entry by ID:
space.unpublishEntry('hello-world').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Crispy bacon news"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "firstPublishedAt": "2013-09-22T23:28:11.503Z",
    "publishedCounter": 1,
    "version": 4,
    "updatedAt": "2013-09-22T23:29:37.122Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Archiving an Entry #

An Entry can only be archived when it's not published.

Archive the Entry with an ID of "hello-world":

space.getEntry('hello-world').then(function(entry) {
  return space.archiveEntry(entry);
}).then(log.ok, log.fail);

// or archive Entry by ID:
space.archiveEntry('hello-world').then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world/archived \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'Content-Length: 0'

Response
{
  "fields": {
    "title": {
      "en-US": "Crispy bacon news"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 3,
    "updatedAt": "2013-09-22T23:28:11.503Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "archivedAt": "2013-09-22T23:28:11.503Z",
    "archivedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "archivedVersion": 2
  }
}

Unarchiving an Entry #

Unarchive the Entry with the ID "hello-world":

space.getEntry('hello-world').then(function(entry) {
  return space.unarchiveEntry(entry);
}).then(log.ok, log.fail);

// or unarchive Entry by ID:
space.unarchiveEntry('hello-world').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world/archived \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Crispy bacon news"
    },
    "body": {
      "en-US": "Bacon is healthy!"
    }
  },
  "sys": {
    "id": "hello-world",
    "type": "Entry",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "blog-post"
      }
    },
    "version": 4,
    "updatedAt": "2013-09-22T23:29:37.122Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Deleting an Entry #

Delete the Entry with the ID "hello-world".

space.getEntry('hello-world').then(function(entry) {
  return space.deleteEntry(entry);
}).then(log.ok, log.fail);

// or delete Entry by ID:
space.deleteEntry('hello-world').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/entries/hello-world \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response

Empty response.

Entry Fields #

Field Type Description
sys Sys See system properties.
sys.contentType Link Link to the Entry's Content Type
fields Object Properties according to Content Type

Assets #

Assets represent files in a Space. An asset can be any kind of file: an image, a video, an audio file, a PDF or any other filetype. Assets are usually attached to Entries through Links.

Assets can optionally be localized by providing separate files for each locale. Those Assets which are not localized simply provide a single file under the default locale.

Creating an Asset #

Create an Asset with ID "bacon-pancakes":

space.createAsset({
  sys: {id: 'bacon-pancakes'},
  fields: {
    title: {'en-US': 'Bacon Pancakes'}
  }
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -d '{"fields":{"title":{"en-US":"Bacon Pancakes"}}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T23:05:03.271Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Listing Assets #

Search Assets in a space:

 space.getAssets().then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/assets \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "sys": {
    "type": "Array"
  },
  "total": 1,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "fields": {
        "title": {
          "en-US": "Bacon Pancakes"
        }
      },
      "sys": {
        "id": "bacon-pancakes",
        "type": "Asset",
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "7daovfk1olns"
          }
        },
        "createdAt": "2013-09-22T23:05:03.271Z",
        "createdBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        },
        "version": 1,
        "updatedAt": "2013-09-22T23:05:03.275Z",
        "updatedBy": {
          "sys": {
            "type": "Link",
            "linkType": "User",
            "id": "0lEP0wVJL8WSQSbRuVUdcJ"
          }
        }
      }
    }
  ]
}

See Search Parameters to learn how to search for specific things.

Getting an Asset #

Get the Asset with an ID of "bacon-pancakes".

space.getAsset('bacon-pancakes').then(log.ok, log.fail);
curl -X GET https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 1,
    "updatedAt": "2013-09-22T23:05:03.275Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Updating an Asset #

Update the Asset with an ID of "bacon-pancakes":

space.getAsset('bacon-pancakes').then(function(asset) {
  asset.fields.file = {'en-US': {
    contentType: 'image/jpeg',
    fileName: 'example.jpg',
    upload: 'https://example.com/example.jpg'
  }};
  return space.updateAsset(asset);
}).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 1' \
     -d '{"fields":{"title":{"en-US":"Bacon Pancakes"},"file":{"en-US":{"contentType":"image/jpeg","fileName":"example.jpg","upload":"https://example.com/example.jpg"}}}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    },
    "file": {
      "en-US": {
        "contentType": "image/jpeg",
        "fileName": "example.jpg",
        "upload": "https://example.com/example.jpg"
      }
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 2,
    "updatedAt": "2013-09-22T23:26:04.733Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Processing an Asset file #

Process the "bacon-pancakes" Asset's en-US file:

space.getAsset('bacon-pancakes').then(function(asset) {
  space.processAssetFile(asset, 'en-US');
});

// or process Asset by ID & version:
space.processAssetFile('bacon-pancakes', 'en-US', 2).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes/files/en-US/process \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 2' \
     -H 'Content-Length: 0'

Asset processing happens asynchronously, the call will not block until it has finished.

Response

Empty response.

Publishing an Asset #

Publish the Asset with an ID of "bacon-pancakes".

space.getAsset('bacon-pancakes').then(function(asset) {
  return space.publishAsset(Asset);
}).then(log.ok, log.fail);

// or publish Asset by ID & version:
space.publishAsset('bacon-pancakes', 2).then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'X-Contentful-Version: 2' \
     -H 'Content-Length: 0'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    },
    "file": {
      "en-US": {
        "contentType": "image/jpeg",
        "fileName": "example.jpg",
        "upload": "https://example.com/example.jpg"
      }
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 3,
    "updatedAt": "2013-09-22T23:28:11.503Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T23:28:11.503Z",
    "publishedCounter": 1,
    "publishedAt": "2013-09-22T23:28:11.503Z",
    "publishedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "publishedVersion": 2
  }
}

After publishing the Asset it will be available via the Content Delivery API.

Unpublishing an Asset #

Unpublish the Asset with the ID "bacon-pancakes".

space.getAsset('bacon-pancakes').then(function(asset) {
  return space.unpublishAsset(asset);
}).then(log.ok, log.fail);

// or unpublish Asset by ID:
space.unpublishAsset('bacon-pancakes').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes/published \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    },
    "file": {
      "en-US": {
        "contentType": "image/jpeg",
        "fileName": "example.jpg",
        "upload": "https://example.com/example.jpg"
      }
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T23:28:11.503Z",
    "publishedCounter": 1,
    "version": 4,
    "updatedAt": "2013-09-22T23:29:37.122Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Archiving an Asset #

An Asset can only be archived when it's not published.

Archive the Asset with an ID of "bacon-pancakes":

space.getAsset('bacon-pancakes').then(function(asset) {
  return space.archiveAsset(asset);
}).then(log.ok, log.fail);

// or archive Asset by ID:
space.archiveAsset('bacon-pancakes').then(log.ok, log.fail);
curl -X PUT https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes/archived \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}' \
     -H 'Content-Length: 0'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    },
    "file": {
      "en-US": {
        "contentType": "image/jpeg",
        "fileName": "example.jpg",
        "upload": "https://example.com/example.jpg"
      }
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "firstPublishedAt": "2013-09-22T23:28:11.503Z",
    "publishedCounter": 1,
    "version": 4,
    "updatedAt": "2013-09-22T23:29:37.122Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "archivedAt": "2013-09-22T23:28:11.503Z",
    "archivedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "archivedVersion": 2
  }
}

Unarchiving an Asset #

Unarchive the Asset with the ID "bacon-pancakes":

space.getAsset('bacon-pancakes').then(function(asset) {
  return space.unarchiveAsset(Asset);
}).then(log.ok, log.fail);

// or unarchive Asset by ID:
space.unarchiveAsset('bacon-pancakes').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes/archived \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response
{
  "fields": {
    "title": {
      "en-US": "Bacon Pancakes"
    },
    "file": {
      "en-US": {
        "contentType": "image/jpeg",
        "fileName": "example.jpg",
        "upload": "https://example.com/example.jpg"
      }
    }
  },
  "sys": {
    "id": "bacon-pancakes",
    "type": "Asset",
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "7daovfk1olns"
      }
    },
    "createdAt": "2013-09-22T23:05:03.271Z",
    "createdBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    },
    "version": 4,
    "updatedAt": "2013-09-22T23:29:37.122Z",
    "updatedBy": {
      "sys": {
        "type": "Link",
        "linkType": "User",
        "id": "0lEP0wVJL8WSQSbRuVUdcJ"
      }
    }
  }
}

Deleting an Asset #

Delete the Asset with the ID "bacon-pancakes".

space.getAsset('bacon-pancakes').then(function(asset) {
  return space.deleteAsset(asset);
}).then(log.ok, log.fail);

// or delete Asset by ID:
space.deleteAsset('bacon-pancakes').then(log.ok, log.fail);
curl -X DELETE https://api.contentful.com/spaces/7daovfk1olns/assets/bacon-pancakes \
     -H 'Content-Type: application/vnd.contentful.management.v1+json' \
     -H 'Authorization: Bearer {{auth.accessToken || "ACCESS_TOKEN"}}'

Response

Empty response.

See Search Parameters to learn how to search for specific things.

Asset Fields #

Field Type Description
sys Sys See system properties.
fields.title Text Title of the Asset.
fields.description Text Description of the Asset.
fields.file File File(s) of the Asset.
fields.file.fileName Symbol Original filename of the file.
fields.file.contentType Symbol Content type of the file.
fields.file.url Symbol URL of the file.
fields.file.details Object Details of the file, depending on its mime type.
fields.file.details.size Number Size (in bytes) of the file.

Arrays #

Search results are represented as Arrays.

Field Type Description
sys Sys See system properties.
total Number Total number of resources matching the search parameters.
limit Number Requested limit parameter.
skip Number Requested skip parameter.

TL;DR

¯\_(ツ)_/¯