> ## Documentation Index
> Fetch the complete documentation index at: https://unkey.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Unkey is two separate products. Compute builds, deploys, and runs apps behind a gateway. API Management issues API keys, enforces rate limits, manages identities and permissions, and reports usage. Say which product a page belongs to; a reader can use either without the other.
> Every Unkey API endpoint is an HTTP POST to https://api.unkey.com/v2/{service}.{procedure} with a root key in the Authorization: Bearer header. Root keys are workspace scoped.
> Error codes have the form err:{system}:{category}:{specific} and each has a page at /errors/{system}/{category}/{specific}.
> The word environment means production or preview in Compute. Rate limiting has four meanings on this site; the glossary lists them.

# Looking up keys

> Read a key's configuration by its id or from the key itself.

Look up a key's settings without verifying it or spending anything. Use `keys.getKey` when you have the key's ID, for example on a management screen. Use `keys.whoami` when you have the key itself, for example when a user pastes it into a support form. Both return the same fields, except `keys.whoami` can't return the decrypted key.

<Note>
  You need a root key with the permissions listed on this page. Create one in the dashboard under **Settings > Root Keys**. See [Permission reference](/docs/platform/root-keys/permissions-legacy) for every permission.
</Note>

Both endpoints need `api.*.read_key` or `api.<api_id>.read_key`. Adding `decrypt: true` to `keys.getKey` additionally needs `api.*.decrypt_key` or `api.<api_id>.decrypt_key`. See [Root key permissions](/docs/platform/root-keys/permissions).

## By identifier

<ParamField body="keyId" type="string" required>
  The `key_...` identifier from `keys.createKey`, a verification response, a listing, or the dashboard. 3 to 255 characters matching `^[a-zA-Z0-9_]+$`.
</ParamField>

<ParamField body="decrypt" type="boolean" default="false">
  Include the plaintext for a key created as recoverable. See [Recoverable keys](/docs/api-management/keys/recoverable-keys).
</ParamField>

```bash theme={"system"}
curl -X POST https://api.unkey.com/v2/keys.getKey \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "keyId": "key_..." }'
```

A key that doesn't exist, is deleted, or belongs to another workspace returns HTTP 404 `err:unkey:data:key_not_found`.

## By plaintext

<ParamField body="key" type="string" required>
  The full key including its prefix, 1 to 512 characters. Any change to it gives a not-found error.
</ParamField>

```bash theme={"system"}
curl -X POST https://api.unkey.com/v2/keys.whoami \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "sk_live_..." }'
```

`keys.whoami` doesn't check whether the key is enabled, expired, or within its limits, and it doesn't record a verification. Use `keys.verifyKey` when you need a verdict.

## Response fields

<ResponseField name="keyId" type="string" required>
  The key's identifier.
</ResponseField>

<ResponseField name="start" type="string" required>
  The prefix and first characters of the key, for display in lists.
</ResponseField>

<ResponseField name="enabled" type="boolean" required>
  Whether the key is enabled.
</ResponseField>

<ResponseField name="createdAt" type="integer" required>
  Creation time as Unix milliseconds.
</ResponseField>

<ResponseField name="updatedAt" type="integer">
  Last update as Unix milliseconds, when the key has been updated.
</ResponseField>

<ResponseField name="lastUsedAt" type="integer">
  Last successful verification as Unix milliseconds. It updates about once a minute, so it can lag real usage by up to a minute.
</ResponseField>

<ResponseField name="name" type="string">
  The internal name.
</ResponseField>

<ResponseField name="meta" type="object">
  The key's metadata.
</ResponseField>

<ResponseField name="expires" type="integer">
  Expiry as Unix milliseconds, when set.
</ResponseField>

<ResponseField name="credits" type="object">
  `remaining` (integer or `null` for unlimited) and, when configured, `refill` with `interval`, `amount`, and `refillDay`.
</ResponseField>

<ResponseField name="ratelimits" type="object[]">
  Each key-level rate limit: `id`, `name`, `limit`, `duration`, `autoApply`.
</ResponseField>

<ResponseField name="permissions" type="string[]">
  Permission slugs the key holds directly or through roles.
</ResponseField>

<ResponseField name="roles" type="string[]">
  Role names assigned to the key.
</ResponseField>

<ResponseField name="identity" type="object">
  When linked: `id`, `externalId`, the identity's `meta`, and its `ratelimits`.
</ResponseField>

<ResponseField name="plaintext" type="string">
  The decrypted key. Returned only by `keys.getKey` with `decrypt: true` on a recoverable key. `keys.whoami` never returns it.
</ResponseField>

```json theme={"system"}
{
  "meta": { "requestId": "req_..." },
  "data": {
    "keyId": "key_...",
    "start": "sk_live_abc1",
    "enabled": true,
    "name": "Acme production",
    "createdAt": 1704067200000,
    "lastUsedAt": 1704153600000,
    "expires": 1767225600000,
    "meta": { "plan": "pro" },
    "credits": {
      "remaining": 9420,
      "refill": { "interval": "monthly", "amount": 10000, "refillDay": 1 }
    },
    "ratelimits": [
      { "id": "rl_...", "name": "requests", "limit": 100, "duration": 60000, "autoApply": true }
    ],
    "permissions": ["documents.read", "documents.write"],
    "roles": ["editor"],
    "identity": { "id": "id_...", "externalId": "org_acme", "meta": {} }
  }
}
```

To page through many keys at once, use `apis.listKeys`, which returns the same objects. See [Listing keys](/docs/api-management/keyspaces/listing-keys).
