---
title: "List API keys"
method: GET
path: "/api/v1/api-keys"
tags: ["ApiKeys"]
---

# List API keys

`GET /api/v1/api-keys`

## Request

- Base URL: `https://app.lastping.dev`
- URL: `https://app.lastping.dev/api/v1/api-keys`
- Auth: API key in header `X-Api-Key`

Returns all API keys for the authenticated project as a JSON array
(never null). The plaintext key value is never included — only the
non-secret `prefix`.

## Response `200`

Array of API keys (may be empty).

- ApiKey[]
  - `id` string, uuid: Unique API key identifier.
  - `name` string: Human-readable label for the key.
  - `prefix` string: First 10 characters of the key — a non-secret identifier shown in place of the full value.
  - `created_at` string, date-time: RFC 3339 UTC timestamp when the key was created.
  - `expires_at` string, date-time: RFC 3339 UTC expiry timestamp, or omitted for a key that never expires.
  - `last_used_at` string, date-time: RFC 3339 UTC timestamp of the most recent request this key authenticated. Omitted if the key has never been used since this field was added — never rendered as a zero/epoch time.
  - `last_used_surface` 'mcp' | 'terraform' | 'api' | 'ingest': Which client surface last used this key, omitted if unknown. `ingest` means the latest use was sending telemetry (traces, metrics or logs); telemetry use is recorded about once a minute per key, so `last_used_at` can trail the newest export by up to a minute. For `mcp`, `terraform` and `api` the value is best-effort and spoofable: derived from the caller-controlled `User-Agent` header on the authenticating request, not from any cryptographic or protocol-level signal. Useful for an honest "did my client ever successfully authenticate?" indicator — never use it for authorization or access control.
  - `scope` 'read' | 'write' | 'admin' | 'ingest': What this key is permitted to do. Always present. Unlike `last_used_surface` above — which is a spoofable hint derived from a caller-supplied header — this is the value the server actually checks. `ingest` sends telemetry only and cannot call this API.
  - `check_id` string, uuid: The one monitor an `ingest` key is bound to. Omitted for an unbound key and for every key of another scope.
  - `created_by_key_id` string, uuid: The API key that minted this one, omitted for a key created from the dashboard (which has no parent key) or whose parent has since been deleted. **Revoking a key revokes every key below it in this chain.** A key minted by a key minted by the key you delete goes with it, all at once. A key created from the dashboard is never below anything and is unaffected.

## Other responses

- `401`: Missing or invalid API key.
- `403`: The API key authenticated, but its scope does not reach this operation. The problem body carries `required_scope`: the tier the operation needs. Re-mint the key at that scope (Settings, `POST /api/v1/api-keys`, or the `create_api_key` MCP tool) rather than retrying — the refusal is deterministic and a retry will be refused identically.
- `429`: Too many requests. The per-principal fixed-window rate limit has been exceeded. Retry after the number of seconds indicated by the `Retry-After` response header. The problem body's `code` is `RATE_LIMITED`. It names this limiter specifically, so a client can tell it apart from the application-level throttles that also answer 429 with their own codes and their own, much longer, `Retry-After` values (`TEST_PING_RATE_LIMITED`, `TOO_MANY_ATTEMPTS`). Back off globally on `RATE_LIMITED`; back off on the one operation for the others. The principal is the API key for a key-authenticated request and the USER for a browser session, so every tab one person has open shares one budget.

---

[API](https://skmtc.dev/lastping/apis/lastping-management-api.md) · [All operations](https://skmtc.dev/lastping/apis/lastping-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lastping/apis/lastping-management-api/revisions/bbc6eda91c46?raw)
