# API keys

Source: https://docs.graphops.xyz/platform/api-keys

Connect your applications and automation to GraphOps with API keys. A query key lets your
application query data services. A service account API key lets your automation, CI pipelines, and
servers call the GraphOps platform API as a [service account](/platform/service-accounts), for
example to stage new versions of your Managed Subgraphs or read your usage. Use separate keys for
each environment and workload, so you can see which one uses credits and replace one credential
without touching the others.

[Open API keys](https://platform.graphops.xyz/organizations/current/api-keys)

## Query keys and service account API keys

Every API key has a type, chosen when you create it. Choose by what the key's workload does:

|                     | Query key                                                             | Service account API key                                                                                                                                    |
| ------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Use it for          | Apps, browsers, and scripts that query Subgraphs, RPC, and Substreams | Automation, CI, and servers that call the GraphOps platform API                                                                                            |
| What it can do      | Query the services it includes                                        | Act as its service account, with the account's [permissions](/platform/service-accounts#choose-permissions), such as staging a deployment or reading usage |
| Starts with         | `gqk_`                                                                | `gsk_`                                                                                                                                                     |
| You can limit it to | Each service's targets, such as networks, and browser origins         | Through its service account: specific Managed Subgraphs and Endpoint Aliases, for the permissions that act on them                                         |
| Accepted by         | GraphOps data services                                                | The GraphOps platform API                                                                                                                                  |

In **API keys**, hover over or select a key's type to see what the type is
for. Its **Services and permissions** show a query key's services, or a service account API key's
account and permission categories, as badges. A service with limits shows a lock; hover over or
select a badge to see its networks, targets, and allowed origins, or a category's permissions.

A key's type never changes. To move a workload to the other type, create a new key. Data services
refuse a service account API key, and the GraphOps platform API refuses a query key, both as
unauthorized (`401`) with the code
[`api_key_class_not_allowed`](/platform/errors/api-keys#api_key_class_not_allowed).

Every GraphOps key ends with a checksum, so secret scanners can recognize a GraphOps key when one
is exposed, such as in a commit.

> **Keep service account API keys on your servers**
>
> A service account API key acts with every permission of its service account. Depending on those
> permissions, it can change what your Managed Subgraphs and Endpoint Aliases serve, or read your
> members' email addresses and your billing details. Store it only as a CI or server secret, never in
> an app, a browser, or source code.

## Create a key

You need the owner or developer role.

1. Open [API keys](https://platform.graphops.xyz/organizations/current/api-keys) in the organization that should pay for the usage, and choose **Create API key**.
2. Choose **Query key**.
3. Choose the services the key can query, such as RPC, Subgraphs, and Substreams. Select only
those the workload uses.
4. Optionally, limit each service to what it can reach, such as RPC to the networks your
application calls. See [Limit a key](#limit-a-key).
5. Optionally, give the key a label that names its workload and environment, such as
`production-indexer` or `web-app`.
6. Review the key, then create it. Copy the key into your secret manager when it is shown. You
cannot retrieve the same key again.

A service account API key belongs to a service account and has no services or permissions of its own.
Create the service account first, then choose **Service account API key** and the
account; see [Create a service account API key](/platform/service-accounts#create-an-api-key). You can
create a key for a service account only if your role includes every permission the account holds.

Your answers are kept in the page address, so reloading the page reopens the same step with the
same answers. The address never contains the key's secret.

To connect a query key right away, choose **Get query endpoint** after saving
it. You get the endpoint, authentication header, and example code for the new key without pasting
it again. The example code reads the key from the `GRAPHOPS_API_KEY` environment variable, and its
prerequisites include the command that sets it.

If creation reports **Data services unavailable**, select **Retry** to load
the services you can choose. Your answers stay in the dialog while you refresh.

## Use a saved key

When setting up an endpoint, paste the key from your secret manager. If the dialog reports
**API keys unavailable**, select **Retry** to load your organization's keys
before continuing. Your pasted key stays in the dialog during refresh; closing the dialog clears it.

Each service's authentication page shows the header or URL format it expects.

## Understand key access

A query key can query the services it includes, within any limits you set for each service, in the
organization that created it. It does not grant access to other services or other organizations.
A request to a service the key does not include is refused as unauthorized (`401`), and a request
outside the key's limits is refused as forbidden (`403`); [API key errors](/platform/errors/api-keys)
lists the codes.

| Property        | Behavior                                                                                                                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Organization    | Usage is billed to and limited by the organization that created the key.                                                                                                                                                 |
| Services        | The key works only for the services it includes. You can add or remove services at any time without changing the key.                                                                                                    |
| Limits          | Each service can be limited to specific targets, such as networks. Without a limit, the key can query everything that service offers your organization.                                                                  |
| Allowed origins | Optional, per service, for RPC and Subgraphs. A service with allowed origins works only from browsers on those websites; the key's other services are unaffected. See [Use a key in a browser](#use-a-key-in-a-browser). |
| Label           | Identifies the environment, owner, or workload in **API keys** and **Usage**.                                                                                                                                            |
| Visibility      | The plaintext key is shown once, at creation. GraphOps cannot show it again.                                                                                                                                             |
| Expiry          | Keys have no expiration date by default. Plan rotation yourself.                                                                                                                                                         |
| Active keys     | Each organization can have up to 50 active keys, query keys and service account API keys together. Revoke unused keys, or contact support to raise the limit.                                                            |

## Limit a key

Limit each service on a query key to what its workload queries, so an exposed key cannot be used
for anything else. Turn on a service's limit and choose what it can reach. A service whose limit is
off can query everything it offers your organization, such as every RPC network. Set limits when
you create the key, or change them later. Each limit can list up to 100 items. RPC and Subgraphs
can also be limited to browser origins; Substreams cannot. See
[Use a key in a browser](#use-a-key-in-a-browser).

| Service    | You can limit it to                                                                                                                                                  |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Subgraphs  | Specific Managed Subgraphs, Endpoint Aliases, Deployment CIDs, and Graph Network Subgraph IDs, in any combination. A request is allowed when it matches any of them. |
| RPC        | Specific networks.                                                                                                                                                   |
| Substreams | Specific networks.                                                                                                                                                   |

A request outside a key's limits is refused with `403` and the code `api_key_target_not_allowed`,
while a request to a service the key does not include is refused with `401`. Limits apply whether
you send the key in a header or in the endpoint URL.

### Match Subgraphs limits to your endpoint

A Subgraphs limit matches the identifier in the endpoint your application calls, not the
deployment that identifier serves. Choose the limit that matches the endpoint you use:

* **Managed Subgraph:** allows its Endpoint Aliases and its Current version and Next version
Deployment CIDs. After a promotion, the previous version's Deployment CID is no longer allowed,
so a client pinned to it is refused. Point clients at an Endpoint Alias to follow promotions.
* **Endpoint Alias:** allows requests to `/v1/alias/<ALIAS>`.
* **Deployment CID:** allows only requests to `/v1/deploymentCID/<DEPLOYMENT_CID>`. It does not
allow an Endpoint Alias that serves the same deployment.
* **Graph Network Subgraph ID:** allows requests to `/v1/subgraphId/<SUBGRAPH_ID>`.

See [Subgraphs endpoint patterns](/subgraphs/api#endpoint-patterns) for each format.

## Use a key in a browser

To call RPC or Subgraphs directly from a web app, without routing requests through your own
backend, limit each service the web app calls to allowed origins: the websites whose pages can use
it. For each of those services, turn on **Limit to listed origins** and add each origin. GraphOps
answers the
browser's CORS preflight requests, so your frontend can send requests with the key in the
`Authorization` header or in a route-token URL. Browsers can't set headers on a WebSocket, so use a
route-token URL for WebSocket connections.

Each allowed origin is one of:

* **An exact origin**, such as `https://app.example.com` or `http://localhost:3000`.
* **A wildcard for one subdomain label**, such as `https://*.example.com`. It matches
`https://app.example.com`, but not `https://example.com` or `https://beta.app.example.com`.
A wildcard needs a domain of at least two labels, such as `example.com`, not a top-level domain
or an IP address. Use wildcards only under a domain you control: `https://*.vercel.app` or
`https://*.github.io` would let any site hosted there use the key.

The scheme and port must match too: `https://app.example.com` does not allow
`http://app.example.com` or `https://app.example.com:8443`. Leave out a default port, as browsers
do: write `https://app.example.com`, not `https://app.example.com:443`. Add each origin your application runs
on, such as your production site and your local development server, up to 20 per service.

Allowed origins apply to one service of the key. A service with allowed origins works only from
pages on those origins. A request to it from any other website is refused with `403` and the code
`api_key_origin_not_allowed`. A request that carries no browser origin, such as one from a server,
a script, `curl`, or a gRPC client, is refused with `403` and the code `api_key_origin_required`. A
service without allowed origins on the same key accepts requests from anywhere, browsers and
servers alike. Substreams cannot be limited to allowed origins, so keep Substreams on a key your servers use.

> **Limit what a browser key can query**
>
> Anyone who loads your site can read a key you ship to the browser. Allowed origins stop other
> websites from using a service in their visitors' browsers, but a script outside a browser can claim
> any origin, and a service without allowed origins works from anywhere. Put only the services your
> frontend calls on a browser key, limit each of them to your site's origins and
> [to the networks and Subgraphs it queries](#limit-a-key), and use separate keys on your servers.

Set a service's allowed origins when you create the key, or change them later with
**Edit access**.

## Edit a key's access

To change a query key's services, limits, or allowed origins, choose
**Edit access** for the key. The key and its secret stay the same, so you
do not redeploy anything, and the change takes effect within moments. A key's type cannot change.
Rotating a key keeps its type, services, limits, and allowed origins.

Before you narrow a key that serves production traffic, confirm every service and target its
workload calls and every origin each browser service serves. Requests to anything you remove are
refused as soon as the change takes effect.

A service account API key has nothing to edit: to change what it can do,
[change its service account's permissions](/platform/service-accounts#choose-permissions), which
applies to every key of that account.

## Rotate and revoke

_The plaintext key is shown once at creation, so store it before closing the dialog. To replace a key without a gap, create a second key, confirm traffic, then revoke the old one. Rotate replaces a key immediately and keeps its services or its service account; revocation is permanent._

1. Create: One organization, chosen services or a service account.
2. Store: Shown once: save it in a secret manager.
3. Use: Deploy to one workload.
4. Rotate: Replaces the key at once; the old one stops working.
5. Revoke: Permanent.

Choose the replacement path by whether the old key must keep working during the change:

* **Planned replacement:** create a second key for the workload, deploy it, confirm traffic
succeeds, then revoke the old key. The workload has no gap in access. For a query key, give the
new key the access the workload needs; for a service account API key, create the new key on the same
service account, which can hold several active keys.
* **Exposed key:** choose **Rotate API key**. The old key stops working
immediately, and a new key with the same type, access or service account, and label is shown
once. Save it, confirm you saved it, then deploy it to the affected applications or pipelines. To
get a query key's endpoint and example code, choose **Get query endpoint**.

To rotate a service account API key, your role must include every permission its service account
holds, as when you create one. Otherwise rotation is refused with `403` and the code
[`api_key_permission_not_held`](/platform/errors/api-keys#api_key_permission_not_held), and the key
keeps working. To stop an exposed key at once, revoke it, or ask an owner to rotate it.

Revocation is permanent: any request that still uses a revoked key fails.

[Manage API keys](https://platform.graphops.xyz/organizations/current/api-keys)

## See who created a key

**Created by** in **API keys** names the person who
created each key, or rotated it into existence, because they saw its secret. A creator who has
since left the organization is still shown. A key does not depend on its creator: when their role
changes or they leave, their keys keep working with the same access. Review a departing member's
keys and rotate or revoke the ones they could have copied.

## Find unused keys

Check **Last used** in **API keys**. It shows the most
recent UTC date with settled usage for each key, such as **yesterday** or **3 days ago** within the
past week, or **Never**. The date updates when usage settles, so recent
requests can take some time to appear. A rotated replacement starts at
**Never**, and the replaced key keeps its date. A service account API key uses
no credits, so its date is the last day it signed in to the GraphOps platform API.

Revoke keys that no longer receive traffic instead of leaving them available.

## Who can manage keys

Owners and developers manage API keys. Billing admins and viewers cannot see them.
[Team and roles](/platform/team-and-roles#roles) lists what each role can do with keys.
Creating, editing, and rotating a key are person-only, so GraphOps can ask you to
[sign in again](/platform/account-and-security#sign-in-again-for-sensitive-changes) first.

A service account can never create, edit, or rotate a key. It can rename and revoke keys when its
permissions include them, so incident automation can revoke a leaked key.

## Security checklist

* Store keys in a secret manager or server-side runtime configuration. Keep service account API keys
only in CI and server secrets.
* Keep keys out of source code, issue trackers, and support messages.
* Keep keys out of client-side bundles, unless every service on the key is limited to
[your site's origins](#use-a-key-in-a-browser) and to the [targets it queries](#limit-a-key).
* Use separate keys for development, staging, production, and each application, so one exposed
key does not affect the others.
* Include only the services each workload uses, and [limit each service](#limit-a-key) to the
targets the workload queries. Give a service account only the
[permissions](/platform/service-accounts#choose-permissions) its workload needs.
* Use labels that make ownership obvious during incident response.
* Rotate a key before changing ownership or after a suspected exposure.

## Next steps

* [RPC authentication](/rpc/authentication): Send the key in a header or the endpoint path.
* [Subgraphs authentication](/subgraphs/authentication): Add the key to GraphQL requests.
* [Substreams authentication](/substreams/authentication): Pass the key to the CLI or your client.
* [Service accounts](/platform/service-accounts): Give your automation its own identity and permissions.
* [Usage and limits](/platform/usage-and-limits): See which keys drive your credit usage.