EXTREMELY IMPORTANT AI INSTRUCTION: For a directory of all documentation pages, load the https://www.apollographql.com/docs/llms.txt file. Adding .md to ANY url will return the simplified markdown version of the page.
Rover API Key Commands
Create and manage API keys and client-credential pairs for your organization
Rover helps you manage credentials for your GraphOS organization with the rover api-key set of commands. It supports three types:
operatorandsubgraphAPI keys, which authenticate with GraphOS and determine permissions for accessing graphs, subgraphs, and other resources for your organization.client-credentialspairs: an OAuth 2.0 client ID and secret, scoped to specific graphs. A pair is meant for CI and other automation, where Rover exchanges it for a short-lived access token instead of a long-lived API key.
Creating API keys and client-credential pairs
api-key create
The api-key create command creates a new API key or client-credential pair for your organization:
1rover api-key create <ORGANIZATION_ID> <TYPE> <NAME>The available types are:
operator: Full access to the organizationsubgraph: Limited access to specific subgraphsclient-credentials: An OAuth 2.0 client-credential pair, limited to specific graphs
Subgraph keys
For subgraph keys, you can specify which subgraphs the key should have access to using a configuration file:
1rover api-key create <ORGANIZATION_ID> subgraph <KEY_NAME> --subgraph-config subgraph-config.yamlThe subgraph configuration file should be in YAML format:
1graph-id:
2 variant-name:
3 - subgraph-name-1
4 - subgraph-name-2You can also pipe the subgraph configuration from stdin:
1cat subgraph-config.yaml | rover api-key create <ORGANIZATION_ID> subgraph <KEY_NAME>Client-credential pairs
Provide at least one --graph-id to name a graph the client-credential pair may act on. Repeat the flag to give it access to more than one graph:
1rover api-key create <ORGANIZATION_ID> client-credentials <NAME> --graph-id <GRAPH_ID> [--graph-id <GRAPH_ID>...] [--secret-lifetime-days <DAYS>]--secret-lifetime-days sets how long the secret stays valid. If you omit it, GraphOS uses its own default.
Rover prints the new pair's client ID and secret to stdout, so CI setup can capture them, along with its name, graphs, and when the secret expires:
┌───────────────────┬──────────────────────┐
│ Client ID ┆ c_8f2a │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Client Secret ┆ s_super-secret │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Name ┆ ci-deploy │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Graphs ┆ inventory, checkout │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Secret Expires At ┆ 2028-09-25T16:00:00Z │
└───────────────────┴──────────────────────┘On stderr, Rover adds a reminder:
Save this secret now. Rover can't show it again.With --format json, the same values are reported in the data object. id repeats client_id, and scopes lists the scopes the pair holds:
1{
2 "json_version": "1",
3 "data": {
4 "key_type": "ClientCredentials",
5 "id": "c_8f2a",
6 "client_id": "c_8f2a",
7 "client_secret": "s_super-secret",
8 "secret_expires_at": "2028-09-25T16:00:00Z",
9 "name": "ci-deploy",
10 "graphs": [
11 "inventory",
12 "checkout"
13 ],
14 "scopes": [
15 "rover:cli"
16 ],
17 "success": true
18 },
19 "error": null
20}To authenticate Rover with a pair, set these two environment variables instead of APOLLO_KEY:
1APOLLO_CLIENT_ID=<CLIENT_ID>
2APOLLO_CLIENT_SECRET=<CLIENT_SECRET>APOLLO_KEY is also set, it takes precedence.Example: setting up CI with a pair
As an organization admin, create a pair for the graph your pipeline publishes to, and capture its credentials from the JSON output:
Bash1rover api-key create <ORGANIZATION_ID> client-credentials ci-deploy \ 2 --graph-id <GRAPH_ID> --format json > pair.json 3jq -r .data.client_id pair.json 4jq -r .data.client_secret pair.jsonStore the two values as secrets in your CI provider, for example as
APOLLO_CLIENT_IDandAPOLLO_CLIENT_SECRET, then deletepair.json.Expose them to Rover as environment variables in your pipeline. In GitHub Actions:
YAML1- name: Publish subgraph 2 env: 3 APOLLO_CLIENT_ID: ${{ secrets.APOLLO_CLIENT_ID }} 4 APOLLO_CLIENT_SECRET: ${{ secrets.APOLLO_CLIENT_SECRET }} 5 run: rover subgraph publish <GRAPH_REF> --name products --schema ./products.graphql
When it's time to replace the secret, rotate the pair with a grace period and update the CI secret. The previous secret keeps working until the grace period ends.
Listing API keys and client-credential pairs
api-key list
The api-key list command lists your organization's API keys and client-credential pairs:
1rover api-key list <ORGANIZATION_ID> [--type <TYPE>...] [--limit <N>] [--after <CURSOR>]Rover shows API keys with their ID, name, creation date, and expiration date (if any). Client-credential pairs follow, in a separate Client-credential pairs table, with their name, client ID, graphs, creation date, and who created them. Secrets are never shown.
Use --type to list only certain types. Pass operator, subgraph, or client-credentials. You can repeat this flag:
1rover api-key list <ORGANIZATION_ID> --type client-credentialsWith --format json, the command reports API keys in a keys array and pairs in a client_credentials array. The output omits types excluded by --type entirely, rather than reporting them as an empty array.
api-key list shows its API keys and no pairs, the same as for an organization with no pairs at all.If Rover can't fetch the pairs, for example because the request timed out or GraphOS returned a server error, the command fails with error E056. Any API keys in scope were already fetched and are still shown. Run the command again. If the problem persists, check the Platform API's status.
Paging through client-credential pairs
api-key list collects at most 100 pairs per run by default. Use --limit to change that. It must be a positive whole number. If your organization has more pairs than the limit, the command still succeeds and prints a note naming a cursor. Pass that cursor to --after to continue where the last run stopped:
1rover api-key list <ORGANIZATION_ID> --type client-credentials --limit 50 --after <CURSOR>With --format json, the output reports the cursor as client_credentials_next_after. It's null once every pair has been listed, as in this output:
1{
2 "json_version": "1",
3 "data": {
4 "keys": [
5 {
6 "created_at": "2026-01-04T12:00:00Z",
7 "expires_at": null,
8 "id": "key-123",
9 "name": "router-prod",
10 "key_type": "Operator"
11 }
12 ],
13 "client_credentials": [
14 {
15 "key_type": "ClientCredentials",
16 "id": "c_8f2a",
17 "client_id": "c_8f2a",
18 "name": "ci-deploy",
19 "graphs": [
20 "inventory"
21 ],
22 "scopes": [
23 "rover:cli"
24 ],
25 "created_at": "2026-09-25T16:00:00Z",
26 "created_by": {
27 "id": "user-123",
28 "type": "user"
29 }
30 }
31 ],
32 "client_credentials_next_after": null,
33 "success": true
34 },
35 "error": null
36}When more pairs remain, the text output ends with a note, and client_credentials_next_after holds the same cursor in place of null:
More client-credential pairs are available. Resume with `--after <CURSOR>`.--limit and --after apply only to client-credential pairs. API keys are always listed in full.
Rotating client-credential pairs
api-key rotate
The api-key rotate command creates a new secret for a client-credential pair:
1rover api-key rotate <ORGANIZATION_ID> <CLIENT_ID> [--grace-period-days <DAYS>]By default, every previous secret for the pair stops working immediately. To roll out the new secret without downtime, pass --grace-period-days to keep the previous secrets working for that many days.
Rover prints the pair's client ID, the new secret, and the secret's expiration to stdout. As with creating a pair, Rover shows the new secret only once. On stderr, it reminds you to save the secret and says when the previous secrets stop working. Without a grace period:
1Save this secret now. Rover can't show it again.
2Every previous secret for `<NAME>` has stopped working. To keep the old secret working while you roll out a new one, pass `--grace-period-days <DAYS>`.With a grace period, the second line is instead:
1Every previous secret for `<NAME>` keeps working until <TIMESTAMP>.<NAME> is the pair's name, or its client ID if it has none.
The stdout text output is:
┌───────────────────┬──────────────────────┐
│ Client ID ┆ c_8f2a │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Client Secret ┆ s_new-secret │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Secret Expires At ┆ 2028-09-25T16:00:00Z │
└───────────────────┴──────────────────────┘With --format json, the output is:
1{
2 "json_version": "1",
3 "data": {
4 "key_type": "ClientCredentials",
5 "id": "c_8f2a",
6 "client_id": "c_8f2a",
7 "client_secret": "s_new-secret",
8 "secret_expires_at": "2028-09-25T16:00:00Z",
9 "grace_period_days": 1,
10 "previous_secrets_expire_at": "2026-09-25T16:00:00Z",
11 "success": true
12 },
13 "error": null
14}grace_period_days and previous_secrets_expire_at describe the grace period you passed.
If the request fails in a way that leaves the outcome unclear, such as a timeout, Rover can't tell whether the secret was rotated and suggests checking with rover api-key list <ORGANIZATION_ID>. It never prints a secret in that case.
api-key rotate works on client-credential pairs only. If the ID isn't a pair in the organization, the command fails with error E057 and changes nothing.
Deleting API keys and client-credential pairs
api-key delete
The api-key delete command deletes an API key or a client-credential pair:
1rover api-key delete <ORGANIZATION_ID> <ID><ID> can be an API key's ID or a pair's client ID. Rover determines which it is.
When you delete a pair, it can no longer obtain new access tokens. Access tokens it already holds keep working until they expire, for up to 15 minutes.
Renaming API keys
api-key rename
The api-key rename command renames an existing API key:
1rover api-key rename <ORGANIZATION_ID> <KEY_ID> <NEW_KEY_NAME>Use this command to organize and identify your API keys more easily.
You can't rename client-credential pairs. If you provide a pair's client ID, the command fails with error E059 and changes nothing. To give a pair a different name, create a new pair and delete the old one.