# List access keys

This operation returns the access keys of your account, newest first, one page at a time. A
listing never includes a key's secret, so it is safe to log, print or hand to a review tool.

Every active key of the account is listed, whatever the calling key itself can reach - a key
limited to one bucket still sees the keys for all buckets. Revoked keys are not listed, and
neither are the keys STRG looks after for you: [the dashboard's own key](https://docs.strg.com/access-keys#the-dashboards-own-key)
and the assistant's.

## When you'd use it

- **An access review.** A scheduled job lists every key with its permissions, buckets and
  creation date, so someone can see at a glance what can reach your data.
- **Cleaning up.** A script finds the keys a finished project or an old CI pipeline left behind -
  by `label` or `createdAt` - and passes their ids to [Delete an access key](https://docs.strg.com/rest-api/delete-access-key).
- **Checking a key is ready.** After creating a key, a deploy script can look at its `regions`
  to see whether it already works everywhere it is needed.

## Request

```http
GET /v1/access-keys?limit=100 HTTP/1.1
Host: api.strg.com
Authorization: Bearer <access key id>:<secret>
```

The calling key needs the **Manage access keys through the API** permission
(`api:access-management`); [Authentication](https://docs.strg.com/rest-api/overview#authentication) has the details.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | The most keys to return, from 1 to 100. Default `100`. |
| `cursor` | string | No | The `nextCursor` of the previous page. Left out for the first page. |

Any other query parameter is ignored.

### Request headers

| Name | Required | Description |
| --- | --- | --- |
| `Authorization` | Yes | `Bearer <access key id>:<secret>` |

## Response

`200 OK`, `Content-Type: application/json`, `Cache-Control: no-store`.

```json
{
  "accessKeys": [
    {
      "id": "STRG8C2R6V1T9Y4H7J5L",
      "label": "ci-uploads",
      "bucketScope": ["my-bucket"],
      "keyPrefix": "builds/",
      "permissions": ["objects:list", "objects:read", "objects:write"],
      "origin": "api",
      "createdAt": "2026-07-02T08:30:12.418Z",
      "regions": { "eu-central-1": "pending" }
    },
    {
      "id": "STRG4N7Q2K9W1X5B8M3D",
      "label": "backup-server",
      "bucketScope": null,
      "keyPrefix": null,
      "permissions": ["objects:list", "objects:read", "objects:write", "buckets:list-all"],
      "origin": "dashboard",
      "createdAt": "2026-06-15T10:00:00.000Z",
      "regions": { "eu-central-1": "active", "us-east-1": "active" }
    }
  ],
  "accountRegions": ["eu-central-1", "us-east-1"],
  "nextCursor": "MTc4MTUxNzYwMDAwMC5TVFJHNE43UTJLOVcxWDVCOE0zRA"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `accessKeys` | array of objects | One page of keys, newest first. Empty when the account has no keys. |
| `accessKeys[].id` | string | The access key id, as an S3 client sends it. |
| `accessKeys[].label` | string or null | The key's name. |
| `accessKeys[].bucketScope` | array of strings or null | The buckets the key reaches, by name. `null` for every bucket. |
| `accessKeys[].keyPrefix` | string or null | The object key prefix the key is limited to, or `null`. |
| `accessKeys[].permissions` | array of strings | The key's [permissions](https://docs.strg.com/access-keys#permissions), by their STRG names. |
| `accessKeys[].origin` | string | Where the key was created: `dashboard`, `mcp` (an MCP client, such as an AI agent) or `api` (this API). |
| `accessKeys[].createdAt` | string | When the key was created, ISO 8601 in UTC. |
| `accessKeys[].regions` | object | Where the key is set up, by region: `active` once it works there, `pending` while it is still being set up. A region that is missing is not set up yet, or not needed by the key. |
| `accountRegions` | array of strings | The regions you store data in. |
| `nextCursor` | string or null | Sent back as `cursor`, it fetches the next page. `null` on the last page. |

A key works in a region once it shows `active` there. Whether a key is ready everywhere it is
needed comes from comparing its `regions` with `accountRegions` - or, for a key limited to
buckets, with the regions those buckets are in. [When a key starts working](https://docs.strg.com/access-keys#when-a-key-starts-working)
explains why a new key takes a moment.

New fields may appear in these objects over time, so a client that skips the fields it does not
recognise keeps working.

### Paging

Keys are ordered by creation time, newest first. A cursor marks a position in that order rather
than a count, so a key created or deleted while you page through neither shifts nor repeats a key
on a later page. A key created after the first page was fetched is not on any later page; a new
listing, from the first page, includes it.

The cursor is opaque: it works when sent back exactly as it was received.

## Errors

When a listing cannot be answered, the status and `code` below say why. Every error is an
`application/problem+json` body, whose shape [Errors](https://docs.strg.com/rest-api/overview#errors) describes.

| Status | `code` | When |
| --- | --- | --- |
| `400` | `invalid_request` | `limit` is not a whole number from 1 to 100. |
| `400` | `invalid_cursor` | `cursor` is not in the form a `nextCursor` takes - changed or cut short on the way, for example. |
| `401` | `unauthenticated` | The `Authorization` header is missing or malformed, the key or secret is wrong, the key is revoked, your account is closed, or the key does not hold **Manage access keys through the API**. The response carries `WWW-Authenticate: Bearer realm="strg.com"`. |
| `429` | `rate_limited` | Too many authentication attempts for this key or from your address. The `Retry-After` header says how many seconds to wait before the next attempt. |
| `500` | `internal_error` | Something went wrong on STRG's side. The same request can be sent again a moment later. |

## Examples

Each example lists every key of the account, following `nextCursor` until it is `null`. The curl version uses `jq` to read the pages.

**curl**

```bash
cursor=""
while :; do
  page=$(curl -sS --fail-with-body -G https://api.strg.com/v1/access-keys \
    -H "Authorization: Bearer $AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
    --data-urlencode "limit=100" \
    ${cursor:+--data-urlencode "cursor=$cursor"}) || { echo "$page" >&2; break; }
  echo "$page" | jq -r '.accessKeys[] | "\(.id)\t\(.label // "")\t\(.createdAt)"'
  cursor=$(echo "$page" | jq -r '.nextCursor // empty')
  [ -z "$cursor" ] && break
done
```

**Python (requests)**

```python
import os

import requests

key_id = os.environ["AWS_ACCESS_KEY_ID"]
secret = os.environ["AWS_SECRET_ACCESS_KEY"]
headers = {"Authorization": f"Bearer {key_id}:{secret}"}

params = {"limit": 100}
while True:
    response = requests.get("https://api.strg.com/v1/access-keys", headers=headers, params=params)
    response.raise_for_status()
    page = response.json()
    for key in page["accessKeys"]:
        print(key["id"], key["label"], key["createdAt"], key["regions"])
    if page["nextCursor"] is None:
        break
    params["cursor"] = page["nextCursor"]
```

**JavaScript (fetch)**

```javascript
const headers = {
  Authorization: `Bearer ${process.env.AWS_ACCESS_KEY_ID}:${process.env.AWS_SECRET_ACCESS_KEY}`,
};

let cursor = null;
do {
  const url = new URL("https://api.strg.com/v1/access-keys");
  url.searchParams.set("limit", "100");
  if (cursor !== null) url.searchParams.set("cursor", cursor);

  const response = await fetch(url, { headers });
  if (!response.ok) {
    const problem = await response.json();
    throw new Error(`${response.status} ${problem.code}: ${problem.detail}`);
  }
  const page = await response.json();
  for (const key of page.accessKeys) {
    console.log(key.id, key.label, key.createdAt, key.regions);
  }
  cursor = page.nextCursor;
} while (cursor !== null);
```

Top-level `await` works when the file is saved with an `.mjs` extension.

## Related

- [Get an access key](https://docs.strg.com/rest-api/get-access-key)
- [Create an access key](https://docs.strg.com/rest-api/create-access-key)
- [Delete an access key](https://docs.strg.com/rest-api/delete-access-key)
- [REST API overview](https://docs.strg.com/rest-api/overview) - authentication, errors, paging and rate limits
- [Access keys](https://docs.strg.com/access-keys) - scope, prefixes and every permission
