Graphdocs

Getting started

Authentication & API keys

Sending a key, and the permissions each key carries.

Every REST and GraphQL request is made with an API key. Keys belong to your workspace (team), not to a person, and each one carries its own set of permissions.

Sending a key

API keys start with graph_ (keys created before the rename to Graph start with ark_ and still work). Send one in either header; they are equivalent:

# Authorization header (recommended)
curl https://api.graphcms.io/v1/content-types \
-H "Authorization: Bearer graph_YOUR_API_KEY"
# Or the X-API-Key header
curl https://api.graphcms.io/v1/content-types \
-H "X-API-Key: graph_YOUR_API_KEY"
1const headers = {
2 Authorization: `Bearer ${process.env.GRAPH_API_KEY}`,
3 'Content-Type': 'application/json',
4};

A request with no key, a key that doesn't start with graph_ or ark_, or a key that has been deleted gets 401:

{ "error": "Unauthorized - Invalid or missing API key" }

Over GraphQL the same failure is a GraphQL error with the code UNAUTHENTICATED.

Creating and managing keys

Keys are managed in the dashboard under Settings → API keys. Creating, editing or deleting keys needs the Manage API keys permission on your own role (owners and admins have it by default).

  • Name and permissions. Every key needs a name and at least one permission. You can only grant permissions your own role has.
  • Shown once. The full key is displayed once, right after you create it. Graph stores only a SHA-256 hash, so it can't be shown again. Lost keys are replaced, not recovered.
  • Editable later. You can rename a key or change its permissions at any time. The key itself doesn't change, so nothing using it needs updating.
  • Deleting revokes. A deleted key stops working on the next request.
  • Last used. The list shows when each key was last used, which helps you find keys nothing needs any more.

Permissions

Each key has one or more of these permissions, chosen when you create it:

PermissionShown asLets the key
content.viewView entriesRead content types and entries: every REST GET, every GraphQL query
content.editCreate and edit entriesCreate entries (REST POST /v1/content, GraphQL createContentEntry) and update them (updateContentEntry)
content.publishPublish and unpublish entriesCreate an entry as published, or move an entry into or out of published
content.deleteDelete entriesdeleteContentEntry
content_types.manageManage content typescreateContentType, updateContentType, deleteContentType
api_keys.manageList API keysThe GraphQL apiKeys query (names, previews and permissions, never the keys)

Any content permission implies content.view: a key that can edit entries can always read them.

Give each key the least it needs. A website that renders content needs only content.view; a CI job that imports posts as drafts needs content.edit; only a trusted publishing workflow should have content.publish.

Missing permissions

A key that is valid but lacks a permission gets 403, and the message names the permission:

{ "error": "Forbidden - this API key needs the \"content.edit\" permission" }

Over GraphQL it is a GraphQL error with the code FORBIDDEN and the same message. Add the permission to the key in Settings → API keys; the key itself stays the same.

Keeping keys safe

  • Keep keys in environment variables or your platform's secret store, never in a repository.
  • Call the API from server code, a build step or a serverless function. A key in browser JavaScript is readable by anyone who opens the page.
  • Use separate keys per site or service, so one can be revoked without breaking the others.
  • If a key leaks, delete it and create a new one.