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 headercurl 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:
| Permission | Shown as | Lets the key |
|---|---|---|
content.view | View entries | Read content types and entries: every REST GET, every GraphQL query |
content.edit | Create and edit entries | Create entries (REST POST /v1/content, GraphQL createContentEntry) and update them (updateContentEntry) |
content.publish | Publish and unpublish entries | Create an entry as published, or move an entry into or out of published |
content.delete | Delete entries | deleteContentEntry |
content_types.manage | Manage content types | createContentType, updateContentType, deleteContentType |
api_keys.manage | List API keys | The 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.