GraphQL API
Use the GraphQL API to request content from Contismo outside the Studio, such as in a website, app, or other external system.
Endpoint
Section titled “Endpoint”Each project environment has its own GraphQL endpoint.
To find the correct endpoint:
- Open your project in the Studio.
- Go to Settings and find the GraphQL endpoint for the environment you want to query.
- Use that URL when configuring your client or integration.
Authentication
Section titled “Authentication”Authenticate requests by sending your API key in the Authorization header:
Authorization: Bearer <your-api-key>Make sure the key you use has access to the project and environment you are querying.
Example query
Section titled “Example query”The following example requests a list of entries from a blogPost model:
query { blogPostCollection(limit: 10) { items { id title body } }}This returns up to 10 items, including the id, title, and body fields for each one.
Query a single entry
Section titled “Query a single entry”To request a single entry, query the model type directly and provide the entry ID:
query { blogPost(id: "entry-id-here") { id title body }}This is useful when you already know which entry you need to retrieve.
Query UI translations
Section titled “Query UI translations”Use the uiTranslations field when your website or app needs reusable interface copy managed in the Studio.
The field returns a list of key-value pairs for a locale:
query { uiTranslations { key value }}By default, this returns values for the project default locale.
When your schema exposes locale enums, you can also pass the optional locale argument to request another locale.
This is useful for front-end strings such as navigation labels, buttons, notices, and shared UI messages.
For details about managing these values in the Studio, see UI Translations.
Mutations (read/write keys)
Section titled “Mutations (read/write keys)”GraphQL mutations require a GraphQL - Read/Write API key (gqlw_ prefix). Read-only keys can query content but cannot run mutations.
Mutations are generated from your content models. For a model with API ID BlogPost, the available operations include:
createBlogPost— create an entryupdateBlogPost— update fields, status, or schedule datesdeleteBlogPost— soft-delete an entry
Global mutations are also available for assets, schema management, and entry translations:
createAsset/deleteAssetcreateContentModel/updateContentModel/deleteContentModelcreateComponent/updateComponent/deleteComponentlinkEntryTranslation/disconnectEntryTranslation
Per-model create mutations accept optional linkToEntryId to create a linked locale variant in one step.
Example: create an entry
Section titled “Example: create an entry”mutation { createBlogPost( locale: "en" status: DRAFT input: { title: "Hello world" body: "First post" } ) { _id _status title }}Example: publish an entry
Section titled “Example: publish an entry”mutation { updateBlogPost( id: "entry-id-here" status: PUBLISHED input: { title: "Hello world" } ) { _id _status }}Example: upload an asset
Section titled “Example: upload an asset”Asset uploads use base64-encoded file content:
mutation { createAsset(input: { filename: "photo.jpg" mimeType: "image/jpeg" contentBase64: "<base64-encoded-bytes>" }) { id url }}How fields and types are named
Section titled “How fields and types are named”GraphQL type names and field names are based on the API IDs configured in the Studio.
That means:
- model API IDs determine the queryable types
- field API IDs determine the fields you can request
If you change API IDs in the Studio, your queries may need to be updated to match.
Good practices
Section titled “Good practices”When working with the GraphQL API, it is usually a good idea to:
- use pagination for larger collections
- request only the fields you actually need
- check model and field API IDs carefully
- account for locale arguments in localized projects, where supported
These practices help keep queries predictable and efficient.
Entry metadata fields
Section titled “Entry metadata fields”Content and taxonomy entry types include underscore-prefixed metadata alongside your model fields. Common examples:
_id: the entry’s identifier_status: delivery status (for example draft, published, or scheduled)_locale: the locale for this entry_localizations: all entries linked as locale variants of the same logical content (same content model, different locales)_workflowStage: when an editorial workflow is configured for the model, the entry’s current workflow stage (apiIdandname). This is separate from_status: the workflow describes editorial progress (e.g. review, approval), while_statusdescribes what is delivered through the API.
Use the schema explorer to see the full set of metadata fields for your project.
Localized entries (translation groups)
Section titled “Localized entries (translation groups)”When your project has multiple locales, related entries can be linked so they represent the same content in different languages. The API does not expose a separate “translation group” type; you work with entries and use _localizations to read linked variants.
Query linked locales
Section titled “Query linked locales”query { blogPost(id: "en-entry-id") { _id _localizations { _id _locale { id } } }}Create a new locale variant
Section titled “Create a new locale variant”Use linkToEntryId on create{Model} to create an entry in another locale and link it to an existing entry:
mutation { createBlogPost( locale: "fr" linkToEntryId: "en-entry-id" input: { title: "Bonjour" } ) { _id _localizations { _id } }}Link two existing entries
Section titled “Link two existing entries”Use global mutations when both entries already exist:
linkEntryTranslation(entryId, peerEntryId)— moveentryIdinto the same group aspeerEntryIddisconnectEntryTranslation(entryId)— removeentryIdfrom its group (other members stay linked)
Both return EntryTranslationMutationResult (a union of your entry types). Use an inline fragment for the model you expect:
mutation { linkEntryTranslation( entryId: "fr-entry-id" peerEntryId: "en-entry-id" ) { ... on Entry_BlogPost { _id _localizations { _id _locale { id } } } }}Replace Entry_BlogPost with the GraphQL type name for your model (shown in the GraphQL Explorer).
Common errors
Section titled “Common errors”| Situation | Error code |
| --------- | ------------ |
| Entries use different content models | BAD_REQUEST |
| Both entries are in the same locale | CONFLICT |
| The group already has an entry for that locale | CONFLICT |
| Entry not found | NOT_FOUND |
Linking and disconnecting require entry update permission (or update-own for entries you created). If another user is actively editing an entry in the Studio, mutations may return ENTRY_EDIT_LOCK_CONFLICT.