Content Delivery API

Content Delivery API #

Introduction #

Hi {{auth.user.firstName}}!

The Content Delivery API is a REST API for delivering content from Contentful to apps, websites and other media. Content is delivered as JSON data; images, videos and other media is delivered as files.

The API is a globally distributed CDN for content: All content, both JSON and binary, is served from the server closest to where a user is requesting content from. This minimizes latency, which especially mobile apps can greatly benefit from. Also, hosting content in multiple datacenters around the world greatly improves the availability of content.

The Content Delivery API is served at cdn.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 for example images.

All content can be securely accessed via HTTPS and will only be delivered if a client authenticates with an access token.

We've also made sure that web apps can access your content directly by means of liberal cross-origin resource sharing.

If you want to manage content through scripts or custom applications use the Content Management API. The Content Delivery API is meant to be used only for delivering content, not managing it.

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 Delivery API.

Getting Started #

All examples provided for other languages are also provided as plain HTTP, so you can use curl in your terminal:

curl -X GET https://cdn.contentful.com/spaces/cfexampleapi?access_token=b4c0n73n7fu1

Hello Content #

We've created a Space and an API key with some example content.

client
// → Client {...}
CDAClient* client = [CDAClient new];
require 'contentful'
client = Contentful::Client.new(
  access_token: 'b4c0n73n7fu1',
  space: 'cfexampleapi'
)

Let's request some data from the example Space:

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

 [client fetchEntryWithIdentifier:@"nyancat"
                          success:^(CDAResponse *response, CDAEntry *entry) {
                            NSLog(@"%@", entry.fields);
                          }
                          failure:^(CDAResponse *response, NSError *error) {
                            NSLog(@"%@", error);
                          }];
client.entry 'nyancat'

You should see something like this (sans some properties for brevity):

{
  "sys": {
    "type": "Entry",
    "id": "nyancat"
  },
  "fields": {
    "name": "Nyan Cat"
  }
}

We've just retrieved our first piece of data and logged it to the console! Creators of cat picture websites rejoice!

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 brower's JavaScript console. 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 #

To get content from the Content Delivery API, clients need to provide an access token. Access tokens are created per Space and are used by clients to access the Space's content.

You can create Access tokens for your own Spaces in the "Content Delivery" tab of the web interface.

The Content Delivery 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:

GET https://cdn.contentful.com/spaces/cfexampleapi
Authorization: Bearer b4c0n73n7fu1


As an URI query parameter named access_token:

GET https://cdn.contentful.com/spaces/cfexampleapi?access_token=b4c0n73n7fu1


For HTTP snippets in this documentation we're going to use the URI query parameter method.

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 #

Specify requested locale as locale URI query parameter.

Let's look at Nyan Cat in Klingon:

GET https://cdn.contentful.com/spaces/cfexampleapi/entries/nyancat?locale=tlh&access_token=b4c0n73n7fu1


{
  "sys": {
    "locale": "tlh"
    ...
  },
  "fields": {
    "name": "Nyan vIghro'"
    ...
  }
}

fields.name is the only localized Field in the cat Content Type, so all other Fields are returned in the default locale.

The locale has to be supported by the Space that's being queried.

The default locale depends on the Space.

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.delivery.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.

Synchronization #

Synchronizing content greatly improves the user experience of applications. Mobile data connections can still be slow and have a very high latency compared to broadband internet connections. When apps sync content to the device and access it from a local database (e.g. CoreData, LocalStorage, SQLite) data access is much faster and apps can provide a much better user experience.

Applications sync periodically: Depending on the use case they may sync every few hours, when being opened or pending user interaction, e.g., on pull to refresh.

To further illustrate this let's think of an example mobile app: A travel guide application which has information about places of interest for a certain area. Users of the travel guide will probably be abroad with a limited data package or no cellular data at all.

Some applications download all available data on every sync, including content they already knew about. This wastes a lot of mobile data and valuable time. This is especially a problem when syncing while on cellular data.

Most applications don't sync at all and require an ongoing internet connection. Many of these apps don't really require a constant connection to work but are still effectively useless when there is no internet. In the case of the travel guide having to hop from wifi to wifi simply to use it would be frustrating.

Instead it makes sense to perform delta updates:

  • Get content which has been added or changed since the last sync
  • Delete local content which has been deleted since the last sync

Compared to the other sync strategies delta updates have many benefits:

  • Use as little data as possible: Most mobile data plans have limits on how much data can be transferred (at full speed) within a given time period. By transferring only actual changes and not transferring everything every time the data footprint of a synchronization is very small. Keeping the sync small also means greatly improved chances of success when a mobile connection is slow.
  • Fast synchronization: Because individual syncs are small they will only take a few seconds at most.
  • As little resource usage as possible: Less data to process also means less resources required for processing the data and less waiting time for users of mobile applications.

To enable delta updates Contentful provides a special synchronization endpoint. This endpoint delivers only new and changed content and notifies about deleted content (deletions). It will never transfer duplicate content the client has already received before.

Endpoint #

A client syncs content by using the sync endpoint. A single sync consists of one or more pages, each a separate request and response.

The first time a client synchronizes content it sends a request to the sync endpoint with the URI query parameter initial set to true:

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?initial=true&access_token=b4c0n73n7fu1


Syncing with initial=true should only be done once for the initial sync when a client has no prior content. This transfers all content from a Space since its creation. The inital sync contains neither deleted content nor deletions.

Syncing specific content #

By default a sync includes all types: Assets, Entries of all Content Types and deletions.

To sync only specific content a type parameter can be specified for the initial sync:

  • all: (default) Include all new and changed content, i.e., Assets, Entries and deletions.
  • Asset: Only include new and changed Assets.
  • Entry: Only include new and changed Entries.
  • Deletion: Only include deletions of Assets and Enties.
  • DeletedAsset: Only include deletions of Assets.
  • DeletedEntry: Only include deletions of Entries.

For Entries you can also specify a content_type parameter. When specifying content_type you must specify type as Entry (meaning that there will be no deletions):

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?initial=true&type=Entry&content_type=cat&access_token=b4c0n73n7fu1


If you want to sync Entries by Content Type you should separately subscribe to a Deletion or DeletedEntry sync to get notified when Entries are deleted:

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?initial=true&type=DeletedEntry&access_token=b4c0n73n7fu1


The type and content_type parameter can only be specified at the initial sync along with the initial parameter. Any subsequent syncs will only include the types you have specified.

Sync responses #

The sync endpoint responds with one or more sync pages, depending on the amount of content that has to be synced. Each sync page includes a list of items along with either a nextPageUrl or a nextSyncUrl.

  • If the page includes a nextPageUrl the current sync has one or more pages after the current one. A client must continually request pages by following nextPageUrl and collect items until it encounters a page with a nextSyncUrl.
{
  "sys": {
    "type": "Array"
  },
  "items": [...],
  "nextPageUrl": "https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=nextpagetoken&access_token=b4c0n73n7fu1"
}


  • If the page includes a nextSyncUrl the current sync is fully complete. The client should store the nextSyncUrl for the next sync. The next sync should be performed depending on the client's use case, i.e., on next app launch, in a few hours or when the user requests a refresh. The final page also includes items. It is important that the client remembers the URL of the next sync in order to effectively sync in the future content without transferring unnecessary data.
{
  "sys": {
    "type": "Array"
  },
  "items": [...],
  "nextSyncUrl": "https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=nextsynctoken&access_token=b4c0n73n7fu1"
}


Sync tokens should be regarded as opaque blobs and simply be passed to the endpoint for the next request.

Syncing & Localization #

When syncing Entries or Assets they come in all available localizations instead of just a single one. Usually Resources coming from the Delivery API only come with a single value per field - the value of the locale you requested or the default one. The Sync endpoint returns all locales per field.

This means that Assets' and Entries' fields will contain an object with values for all available locales instead of a single value like most other Delivery API endpoints. Their fields look similar to the fields in the Content Management API.

For example, if you want to access the name field of a synced Entry:

Instead of accessing just fields.name use fields.name['en-US'] instead.

Let us know if you need a way to sync only a single locale.

Item types #

The items included in a sync response are a list of resources with different types:

  • Entry: An Entry that was created or changed.
  • Asset: An Asset that was created or changed.
  • DeletedEntry: An Entry that was deleted.
  • DeletedAsset: An Asset that was deleted.

Deletions have sys.id and sys.type just like other resources. For example, if an Entry with sys.id = "foo" is deleted there will be a deletion with sys.type = "DeletedEntry" and sys.id = "foo". Whenever a client encounters a deletion of a resource it should remove that resource locally. Note that a deletion doesn't carry any of its prior resource's original information other than type, ID and deletion time.

Note on syncing Content Types #

For syncing Content Types clients should use the usual Content Type search endpoint.

Example sync flow #

To further illustrate synchronization let's perform the initial synchronization and a subsequent synchronization of a Space.

Initial sync request #

First let's make the initial sync request:

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?initial=true&access_token=b4c0n73n7fu1


This will result in the first batch of items:

{
  "sys": {
    "type": "Array"
  },
  "items": [...],
  "nextPageUrl": "https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=secondpage&access_token=b4c0n73n7fu1"
}


The initial page's response includes a nextPageUrl. This means this sync is not over yet and we need to request the next page.

Requesting the next page #

The next page's URL we got from the previous page so let's request that:

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=secondpage&access_token=b4c0n73n7fu1


The response yields the second batch of items:

{
  "sys": {
    "type": "Array"
  },
  "items": [...],
  "nextSyncUrl": "https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=nextsync&access_token=b4c0n73n7fu1"
}


The second page's result includes a nextSyncUrl. This means the sync is complete and we should store its URL for the next sync.

Subsequent synchronizations #

In the previous sync we got a nextSyncUrl. Let's request this URL to learn about changes that happened since the previous sync:

GET https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=nextsync&access_token=b4c0n73n7fu1


The result will look like one of the pages of the initial sync, and again depending on whether a page has a nextPageUrl or a nextSyncUrl we must request either the next page or end syncing and store the nextSyncUrl for later use.

If for some reason a client loses the nextSyncUrl the client should delete its local content and perform the initial synchronization again.

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.

Request Format #

When content is published or unpublished all webhooks in a Space are fired. Each webhook has a URL which will receive an HTTP POST request. The HTTP request has the following headers & request body:

Headers of Webhook HTTP Request #

The X-Contentful-Topic header is one of the following values, depending on which type of Resource has been published or unpublished:

  • ContentManagementAPI.ContentType.publish
  • ContentManagementAPI.ContentType.unpublish
  • ContentManagementAPI.Entry.publish
  • ContentManagementAPI.Entry.unpublish
  • ContentManagementAPI.Asset.publish
  • ContentManagementAPI.Asset.unpublish

For example, when an Entry has been published:

X-Contentful-Topic: ContentManagementAPI.Entry.publish

Body of Webhook HTTP Request #

The request body is the published Resource's body or deletion thereof.

The request body's content depends on the specific action:

  • On activate/publish: The Resource's body. In case of Entries and Assets their fields will contain all locales, e.g. instead of fields.name there will be fields['en-US'].name.
  • On deactivate/unpublish: The Deletion of the Resource.

For Example, when an Entry has been published:

{
  "sys": {
    "type": "Entry",
    "id": "cat",
    "space": {"sys": {"type": "Link", "linkType": "Space", "id": "example"}},
    "contentType": {"sys": {"type": "Link", "linkType": "ContentType", "id": "cat"}},
    "createdAt": "2013-03-26T00:13:37.123Z",
    "updatedAt": "2013-03-26T00:13:37.123Z",
    "revision": 1
  },
  "fields": {
    "name": {"en-US": "Nyan cat"},
    "color": {"en-US": "Rainbow"},
    "nyan": {"en-US": true},
    "birthday": {"en-US": "2011-04-02T00:00:00.000Z"},
    "diary": {"en-US": "Nyan cat has an epic rainbow trail."},
    "likes": {"en-US": ["rainbows", "fish"]},
    "bestFriend": {"en-US": {"type": "Link", "linkType": "Entry", "id": "happycat"}}
  }
}

Or a Deletion of an Entry when an Entry has been unpublished:

{
  "sys": {
    "type": "DeletedEntry",
    "id": "cat",
    "space": {"sys": {"type": "Link", "linkType": "Space", "id": "example"}},
    "createdAt": "2013-03-26T00:13:37.123Z",
    "updatedAt": "2013-03-26T00:13:37.123Z",
    "revision": 1
  }
}

Response Detection #

When a webhook is triggered an HTTP POST request is made to its pre-configured HTTP URL. Depending on the HTTP response's status code the webhook will either succeed or fail:

  • Success: The HTTP endpoint responded with an HTTP status code < 300
  • Error: The HTTP endpoitn responded with an HTTP status code >= 300

In case of an error, the webhook will periodically retry its request with increasing delays inbetween up to a maximum of 3 attempts.

HTTP Details #

Security #

The Content Delivery 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.

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.

ETag/If-None-Match #

The API support conditional GET-requests via ETag & If-None-Match headers:

Every API response (both single resources and searches) includes an ETag header. The ETag header changes depending on the content of the response: If something is updated or a search result changes in some way the ETag also changes. But if nothing changes the ETag also stays the same.

To avoid unnecessary transfers you can set the If-None-Match header of an API request to a the ETag previously received for the same API request.

If the content hasn't changed in the meantime the API will respond with a short 304 Not Modified response. This makes quite a difference for large responses and especially binary files.

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.

Errors #

The API has a set of well-defined errors that it responds with if something didn't work out:

  • 404 Not Found: The requested resource or endpoint could not be found.
  • 400 Bad Request: The request was malformed or missing a parameter.
  • 403 Acess Denied: The client is not allowed to perform the requested action.
  • 401 Unauthorized: The client did not send an access token as authorization.
  • 500 Server Error: Something went wrong on our end.

Error Fields

Field Type Description
sys.type String Always "Error".
sys.id String ID of error (one from the list above).
details Object Details, depending on the error's ID.

You should always handle errors according to their sys.id instead of their HTTP status code. Future errors might be added which map to existing status codes but have different meanings.

Endpoints #

List of all endpoints:

Method Path See also
GET /spaces/:space_id Getting a Space
GET /spaces/:space_id/content_types Searching Content Types
GET /spaces/:space_id/content_types/:id Getting a Content Type
GET /spaces/:space_id/entries Searching Entries
GET /spaces/:space_id/entries/:id Getting an Entry
GET /spaces/:space_id/assets Searching Assets
GET /spaces/:space_id/assets/:id Getting an Asset
GET /spaces/:space_id/sync Synchronization

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 #

The API follows REST principles and provides entities as resources. All resources have descriptive URLs that speak for themselves.

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

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

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

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

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

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.revision Integer Version of resource.
sys.createdAt Date Time entity was created.
sys.updatedAt Date Time entity was updated.

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. For example, you could have a Space with an Entry with ID = "foobar" and a Content Type with ID = "foobar".

Spaces #

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

Getting a Space #

client.space().then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi?access_token=b4c0n73n7fu1

[client fetchSpaceWithSuccess:^(CDAResponse* response, CDASpace* space) {
  NSLog(@"sys = %@\nlocales = %@", space.sys, space.locales);
  [NSApp terminate:nil];
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"Error: %@", error);
  [NSApp terminate:nil];
}];
client.space

Response

{
  "sys": {
    "type": "Space",
    "id": "cfexampleapi"
  },
  "name": "Contentful Example API",
  "locales": [
    {"code": "en-US", "name": "English"},
    {"code": "tlh", "name": "Klingon"}
  ]
}

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.

Note: They're not related to the HTTP Content-Type header.

Getting a Content Type #

Get a Content Type with the ID "cat".

client.contentType('cat').then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/content_types/cat?access_token=b4c0n73n7fu1

[client fetchContentTypeWithIdentifier:@"cat" success:^(CDAResponse* r, CDAContentType* ct) {
  NSLog(@"%@\nfields: %@", ct, ct.fields);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"Error: %@", error);
}];
 client.content_type('cat')

Response (sans some properties):

{
  "sys": {
    "type": "ContentType",
    "id": "cat"
  },
  "name": "Cat",
  "description": "Meow.",
  "fields": [
    {"id": "name", "name": "Name", "type": "Text"},
    {"id": "diary", "name": "Diary", "type": "Text"},
    {"id": "likes", "name": "Likes", "type": "Array", "items": {"type": "Symbol"}},
    {"id": "bestFriend", "name": "Best Friend", "type": "Link"},
    {"id": "lifes", "name": "Lifes left", "type": "Integer"}
  ]
}

Searching Content Types #

Search Content Types in a space.

client.contentTypes().then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/content_types?access_token=b4c0n73n7fu1

[client fetchContentTypesWithSuccess:^(CDAResponse *response, CDAArray *array) {
  NSLog(@"%@", array);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"Error: %@", error);
}];
client.content_types

The response is an Array of Content Types (sans some properties):

{
  "sys": {
    "type": "Array"
  },
  "total": 4,
  "skip": 0,
  "limit": 100,
  "items": [...]
}

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

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.
Number 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.

Field type are modelled as an enumeration in the Objective-C SDK:

Value Objective-C value type
CDAFieldTypeArray NSArray
CDAFieldTypeBoolean NSNumber
CDAFieldTypeDate NSDate
CDAFieldTypeInteger NSNumber
CDAFieldTypeLink CDAResource
CDAFieldTypeLocation NSData with CLLocationCoordinate2D struct
CDAFieldTypeNumber NSNumber
CDAFieldTypeSymbol NSString
CDAFieldTypeText NSString

Entries #

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

Getting an Entry #

Get an Entry with an ID of "nyancat".

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

[client fetchEntryWithIdentifier:@"nyancat" success:^(CDAResponse *response, CDAEntry *entry) {
  NSLog(@"%@", entry.fields);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"Error: %@", error);
}];
client.entry('nyancat')

Response (sans some properties):

{
  "sys": {
    "type": "Entry",
    "id": "cat",
    "space": {"sys": {"type": "Link", "linkType": "Space", "id": "example"}},
    "contentType": {"sys": {"type": "Link", "linkType": "ContentType", "id": "cat"}},
    "createdAt": "2013-03-26T00:13:37.123Z",
    "updatedAt": "2013-03-26T00:13:37.123Z",
    "revision": 1
  },
  "fields": {
    "name": "Nyan cat",
    "color": "Rainbow",
    "nyan": true,
    "birthday": "2011-04-02T00:00:00.000Z",
    "diary": "Nyan cat has an epic rainbow trail.",
    "likes": ["rainbows", "fish"],
    "bestFriend": {"type": "Link", "linkType": "Entry", "id": "happycat"}
  }
}

Searching Entries #

Search Entries in a space.

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

[client fetchEntriesWithSuccess:^(CDAResponse *response, CDAArray *array) {
  NSLog(@"total: %d\nskip: %d\nlimit: %d", array.total, array.skip, array.limit);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"%@", error);
}];
client.entries

The response is an Array of Entries (sans some properties):

{
  "sys": {
    "type": "Array"
  },
  "total": 2,
  "skip": 0,
  "limit": 100,
  "items": [...]
}

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.

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.

When querying the Content Delivery API for Entries which contain Links to Assets then all Assets will be included by default.

Resize image assets on the fly by supplying the desired dimensions as query parameters.

Assets included by default #

When searching Entries which contain Links to Assets the linked Assets will be included in the response by default.

Image Asset resizing #

Instead of chosing image dimensions in Content Management you can specify the dimensions of images during delivery.

Images are hosted on images.contentful.com. For files on this host you can attach the URI query parameters w and/or h to specify the desired dimensions. The image will never be stretched, skewed or enlarged. Instead it will be fit into the bounding box given by the w and h parameters.

Additionaly, a q can be passed to define the JPEG compression quality between 1 and 100 and the fm parameter can be used to change the format to either "png" or "jpg".

GET https://images.contentful.com/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png?w=100&fm=jpg&q=50

GET https://images.contentful.com/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png?w=100&fm=jpg&q=50

[asset imageURLWithSize:CGSizeMake(300.0, 200.0)];
[asset imageURLWithSize:CGSizeMake(300.0, 200.0)
                quality:100
                 format:CDAImageFormatJPEG];
client.asset('happycat').image_url(width: 300, height: 200, format: 'jpg', quality: 100)

Getting an Asset #

Get Asset with ID "nyancat".

client.asset('nyancat').then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/assets/nyancat?access_token=b4c0n73n7fu1

[client fetchAssetWithIdentifier:@"nyancat" success:^(CDAResponse *response, CDAAsset *asset) {
  NSLog(@"%@", asset);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"%@", error);
}];
client.asset('nyancat')

Response (sans some properties):

{
  "sys": {
    "type": "Asset",
    "id": "nyancat",
    "space": {"sys": {"type": "Link", "linkType": "Space", "id": "example"}},
    "createdAt": "2013-03-26T00:13:37.123Z",
    "updatedAt": "2013-03-26T00:13:37.123Z",
    "revision": 1
  },
  "fields": {
    "title": "Nyan cat",
    "description": "A typical picture of Nyancat including the famous rainbow trail.",
    "file": {
      "fileName": "nyancat.png",
      "contentType": "image/png",
      "details": {
        "image": {
          "width": 250,
          "height": 250
        },
        "size": 12273
      },
      "url": "//images.contentful.com/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png"
    }
  }
}

Searching Assets #

Search Assets in a space.

client.assets().then(log.ok, log.fail);
GET https://cdn.contentful.com/spaces/cfexampleapi/assets?access_token=b4c0n73n7fu1

[client fetchAssetsWithSuccess:^(CDAResponse *response, CDAArray *array) {
  NSLog(@"%@", array);
} failure:^(CDAResponse *response, NSError *error) {
  NSLog(@"%@", error);
}];
client.assets

The response is an Array of Assets (sans some properties):

{
  "sys": {
    "type": "Array"
  },
  "total": 2,
  "skip": 0,
  "limit": 100,
  "items": [...]
}

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

¯\_(ツ)_/¯