GraphQL - Introduction
Base URL
- AWS North America (AWS NA): https://graphql.contentstack.com/
- AWS Europe (AWS EU): https://eu-graphql.contentstack.com/
- AWS Australia (AWS AU): https://au-graphql.contentstack.com/
- Azure North America (Azure NA): https://azure-na-graphql.contentstack.com/
- Azure Europe (Azure EU): https://azure-eu-graphql.contentstack.com/
- GCP North America (GCP NA): https://gcp-na-graphql.contentstack.com/
- GCP Europe (GCP EU): https://gcp-eu-graphql.contentstack.com/
Base URLs for Live Preview
The GraphQL Content Delivery API offers live preview functionality, enabling users to view real-time previews of their content. To make use of this feature, use the following endpoints for different regions:
- AWS North America (AWS NA): https://graphql-preview.contentstack.com/
- AWS Europe (AWS EU): https://eu-graphql-preview.contentstack.com/
- AWS Australia (AWS AU): https://au-graphql-preview.contentstack.com/
- Azure North America (Azure NA): https://azure-na-graphql-preview.contentstack.com/
- Azure Europe (Azure EU): https://azure-eu-graphql-preview.contentstack.com/
- GCP North America (GCP NA): https://gcp-na-graphql-preview.contentstack.com/
- GCP Europe (GCP EU): https://gcp-eu-graphql-preview.contentstack.com/
Additional Resource You can refer to our documentation on Live Preview for more information.
Overview
GraphQL Content Delivery API is a more efficient alternative to the Content Delivery APIs. It lets you fetch customized responses or retrieve data of nested or multiple resources through a single API request.
GraphQL is a flexible, customizable API query language. Contentstack’s GraphQL API gives you the power to query for exactly what you need and nothing more, for instance, you can even fetch data from multiple content types via a single API request. You can customize your responses by defining the structure of your requests. Currently, Contentstack GraphQL supports only queries and each requested resource’s GraphQL types are generated in real time, so your content remains current.
Note Contentstack's GraphQL API does not support mutations and subscriptions.
Warning Avoid using _regex or _exists in field UIDs. These are reserved keywords in GraphQL and may cause errors during queries. Use alternative naming to ensure smooth query execution.
If you are familiar with GraphQL, and want to get a hands-on experience of the API, here’s a quick link to our sample stack:
Authentication
GraphQL API requests must be authenticated using the following details:
- Stack API key
- Environment
- Delivery token of the concerned environment
You need to pass the stack API Key in the URL and the publishing environment as a query parameter. Use the value of the delivery token against the access_token key in the header to authenticate your API request.
Note To fetch entries of a specific branch in your stack, you can pass the branch header while running the API request. This is an optional header that accepts the branch unique ID as value. You can also pass the alias ID as value for the branch header while querying the GraphQL API. If the branch header is not passed, then the API fetches details from the main branch by default.
The API Key is a unique key assigned to each stack. The delivery token is a read-only token, meaning this token can be used to fetch published content only, and not to edit or create new content in your stack.
Rate Limiting
Rate limiting defines the maximum number of API requests your organization can make within a specific time frame.
Request Types
• CDN Requests: Contentstack’s CDN serves cached responses. These requests are not subject to rate limiting.
• Origin Server Requests: Requests that are not cached and are routed to the origin server are subject to rate limits.
Default Limits
By default, origin server requests are limited to 80 requests per second per organization. All requests made from the GraphQL API endpoint counts towards this rate limit. The exact rate limit depends on your plan. If required, you can request an increase by contacting support.
Note While CDN requests are not rate-limited, all API requests (CDN and origin) count toward your organization’s overall API usage quota.
Rate Limit Exceeded
If your application exceeds the allowed rate limit within a given time period, the API will return an HTTP 429 (Too Many Requests) response.
Monitoring Rate Limits
You can track your current rate limit status using the HTTP response headers returned with each API request. These limits reset at the beginning of each time window.
| Headers | Description |
|---|---|
| X-RateLimit-Limit | Maximum number of requests allowed per second per organization. |
| X-RateLimit-Remaining | Number of requests remaining in the current time window. |
Anatomy of a GraphQL Query
Let’s look at the basic parts of a simple GraphQL query.
- Operation Type: GraphQL queries use the query keyword to indicate the type of operation we are performing.
- Arguments: An argument consists of a parameter-value set that can be used to specify arguments such as locale, skip, limit, where (conditions), etc.
- Fields: You can define the set of data for which you are asking.
The above query would look as follows when written in the form of a request:
https://graphql.contentstack.com/stacks/blt95a0a7afb9613f51?environment=production&query={all_product(where: {title: Galaxy Note}) { items { title description } } }
Within this API request, we state the stack API key and the publishing environment, followed by your query. The delivery token is passed as value of the access_token key in the header.
Note To fetch entries of a specific branch in your stack, you can pass the branch ID as value of the optional branch key in the header.
API Conventions
- The Contentstack GraphQL Content Delivery API is available at the following endpoints:
- North America: https://graphql.contentstack.com/stacks/{stack_api_key}?environment={environment_name}
- Europe: https://eu-graphql.contentstack.com/stacks/{stack_api_key}?environment={environment_name}
- Azure North America: https://azure-na-graphql.contentstack.com/stacks/{stack_api_key}?environment={environment_name}
- Azure Europe: https://azure-eu-graphql.contentstack.com/stacks/{stack_api_key}?environment={environment_name}
- GCP NA: https://gcp-na-graphql.contentstack.com/stacks/{stack_api_key}?environment={environment_name}
- Dedicated Infrastructure (DI): https://{DI}.graphql.contentstack.com/{region}
- To fetch content from Contentstack, use the endpoint for the region where your organization data resides.
- Pass the delivery token of the concerned environment in the following header while making an API request:
access_token: "{delivery_token}" - Pass the unique ID of a branch to which a content type belongs against the following header to fetch branch-specific content:
branch: "{branch_ID}"
Note This is an optional header.
- The Contentstack GraphQL API endpoint for both entries and assets is the same. It can be used to fetch content (both entries and assets) across multiple content types.
HTTP Methods
Contentstack’s GraphQL Content Delivery API supports both GET and POST methods on the GraphQL endpoint.
Let us understand how these methods work.
The GET Method
For GET requests, you must pass an environment name and a query in the request URL. Optionally, you can also specify an operation name or variable.
URL: https://{{domain}}/stacks/{{api_key}}
Method: GET
Headers:
- access_token: {{env_delivery_token}}
- branch: {{branch_ID}} (optional)
Parameters:
- environment={{environment_name}} (mandatory)
- query={{...}} (mandatory)
- variables={ "myVariable": "someValue", ... } (optional)
- operationName={{...}} (optional)
Here’s a sample cURL for a GraphQL GET request:
curl -g \
-X GET \
-H "Content-Type: application/json" \
-H "access_token: {{env_delivery_token}}" \
-H "branch: {{branchName || branchAlias}}" \
'https://graphql.contentstack.com/stacks/{{api_key}}?environment={{environment_name}}&query=query($locale:String){all_blog(locale:$locale){items{title}}}&variables={"locale":"en-us"}'
The POST Method
For POST requests, you must pass an environment name in the request URL, while the request body must include a query. Optionally, you can also specify an operation name or variable.
URL: https://{{domain}}/stacks/{{api_key}}
Method: POST
Headers:
- access_token: {{env_delivery_token}}
- branch: {{branch_ID}} (optional)
Parameters:
- environment={{environment_name}} (mandatory)
Body:
{
"query": "...", # Mandatory
"operationName": "...", # Optional
"variables": { "myVariable": "someValue", ... } # Optional
}
Here’s a sample cURL for a GraphQL POST request:
curl -g \
-X POST \
-H "Content-Type: application/json" \
-H "access_token: {{environment_delivery_token}}" \
-H "branch: {{branchName || branchAlias}}" \
-d '{"query":"query($locale: String){all_blog(locale: $locale){items{title}}}","variables":{{"locale":"en-us"}}}' \
https://graphql.contentstack.com/stacks/{{api_key}}?environment={{environment_name}}Error Handling
GraphQL separates the success of the HTTP request from the success of the query it carries. A request can reach the GraphQL Content Delivery API, execute, and return HTTP 200 OK while the response body reports that part or all of the query failed. The HTTP status code describes the transport, and the response body describes the operation.
Note Treat HTTP 200 as confirmation that the server received and processed the request, not as confirmation that the query succeeded. Always inspect the response body for an errors key before you use the data.
Response Shapes
Every response from the GraphQL Content Delivery API takes one of the following shapes.
| Outcome | Response Shape | HTTP Status Code |
|---|---|---|
| The query succeeded. | data contains the requested fields. There is no errors key. | 200 |
| The query partially succeeded. | data contains the fields that resolved, and errors lists the fields that failed. Failed fields are null inside data. | 200 |
| The query failed during execution. | data is null, and errors describes the failure. | 200 |
| The request never executed. | The body carries an error and no data key. | 4xx or 5xx |
A partial response is the shape that most often goes unnoticed. The request returns 200, the payload contains a data object, and a client that checks only the status code treats the response as complete content.
In the following example, the title field resolved, the author reference did not, and errors names the exact field that failed through its path:
{
"data": {
"all_article": {
"items": [
{
"title": "Sustainable Cities",
"author": null
}
]
}
},
"errors": [
{
"message": "Failed to run query.",
"path": ["all_article", "items", 0, "author"],
"locations": [{ "line": 5, "column": 9 }],
"extensions": {
"errors": [
{
"code": "error_code",
"message": "Message.",
"details": {
"hint": "Hint to resolve the issue."
}
}
]
}
}
]
}
Keys in the Errors Array
Each object in the errors array can contain the following keys:
- message: Human-readable description of what failed.
- path: Location of the failed field within the data object, expressed as the sequence of field names and list indexes that lead to it. Use this key to identify which part of the query failed.
- locations: Line and column of the failing selection within the query string.
- extensions: Contentstack-specific detail, including the nested errors array that carries code, message, and details.hint.
Checking for Errors in Your Client
A client that treats any HTTP 200 as a success renders empty or partial content instead of raising the underlying failure. The following example checks the status code and the errors key before it returns data. Replace DELIVERY_TOKEN with the delivery token from your stack settings, and set endpoint to the base URL for your region.
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
access_token: DELIVERY_TOKEN, // Replace with the delivery token from your stack settings
},
body: JSON.stringify({ query }),
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const result = await response.json();
if (result.errors?.length) {
// The request succeeded, but the query did not. Handle before using result.data.
console.error("GraphQL errors:", JSON.stringify(result.errors, null, 2));
throw new Error(result.errors[0].message);
}
return result.data;
Tip Log the full errors array rather than the first message alone. A single response can report several independent field failures, and path tells you which fields to re-query.
Error Handling in GraphQL Clients
Most GraphQL client libraries parse the errors key for you and expose it through their own abstraction. Libraries differ in how they treat a response that carries both data and errors, and several discard the partial data by default and surface only the failure. A query that returns partial content can therefore reach your application as a complete failure.
Before you rely on a client library, establish the following:
- Whether the library exposes partial data alongside the error, or discards it.
- Whether that behavior is configurable, and which setting your application requires.
- How the library exposes the individual entries of the errors array, so that you can read message and path.
Warning Do not map a client-side GraphQL error directly onto an HTTP status in your own application. A handler that converts any query error into a “not found” response turns a single failed field into a 404 for your end users, even though the rest of the content resolved. Inspect the individual errors first, then decide how to respond.
Common Causes of HTTP 200 With Errors
The following conditions produce an errors array alongside HTTP 200:
- A referenced entry or asset fails to resolve while the parent entry resolves successfully.
- A resolver exceeds the server’s execution budget for the query.
- The query requests a field that does not exist on the type, or omits a selection set on a non-leaf field.
- The query contains several operations and does not specify operationName.
- A non-nullable field resolves to null, which nullifies the field’s nearest nullable parent.
Conditions that the server rejects before it executes the query return a non-2xx status instead. These include authentication failures, invalid branches and locales, and the plan-based limits on documents, resolver cost, content types, and reference depth.
Additional Resources:
- For the full list of Contentstack error codes and messages, refer to Errors in GraphQL.
- For a general introduction to GraphQL error semantics, refer to Common HTTP Errors and How to Debug Them in the official GraphQL documentation.
Introspection
Introspection system offers the ability to introspect what type of queries can run on the generated GraphQL schema. It provides a detailed description of the different object types that can be fetched from the schema.
For example, each content type in your stack has a corresponding GraphQL type and name. The introspection system would help you understand what fields can be queried, the arguments supported by those fields, and what output types can be returned by them.
We recommend that you structure your GraphQL queries by referring to the introspection schema. To explore the schema, you can run the following introspection query in Contentstack’s GraphiQL explorer:
query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
You can also paginate the response schema returned by the Introspection system by passing the skip and limit parameters in the query. By default, the content types in the schema are sorted based on title_ASC and cannot be modified.
Note The 'SysAsset' GraphQL type will not be available in the paginated Introspection queries.
To skip certain content types when retrieving content, you can make use of the skip_content_type_uids=[] query parameter. You need to pass an array of content type UIDs to this parameter. This parameter comes really handy when you encounter a SCHEMA_BUILD_ERROR during introspection queries. Using it, you can skip the content type(s) causing the schema build error and view the rest of your stack data.
GraphiQL Explorer
Contentstack’s GraphiQL explorer allows you to explore the GraphQL Content Delivery API. You can structure your GraphQL queries based on the available schema and test them out.
The GraphiQL explorer provides information about the content types and fields that are part of the schema.
You can also enter your own stack details and the required parameters in the GraphQL Explorer to try out the API.
Using Postman Collection
Contentstack offers you a Postman Collection that helps you try out our GraphQL Content Delivery API. You can download this collection, connect to your Contentstack account, and try out the GraphQL API with ease.
Learn more about how to get started with using the Postman Collection for Contenstack GraphQL Content Delivery API.