---
title: "API keys"
description: "`keys.list`, `listAll`, `iterate`, `get`, `create`, `update`, `delete`, `rotate` and `revoke`, and the request log and activity readers."
url: "https://openemail.uk/docs/sdk/keys"
area: "SDK"
category: "Mailbox"
---

# API keys

`keys.list`, `listAll`, `iterate`, `get`, `create`, `update`, `delete`, `rotate` and `revoke`, and the request log and activity readers.

## Every method

**keys.ts**

```
const key = await openemail.keys.create({
  name: 'Billing sender',
  scopes: ['emails:send'],
  domainAllowlist: ['billing.acme.com'],
  expiresInMinutes: 60 * 24 * 90,
})

await store(key.token)

await openemail.keys.update(key.id, { enabled: false })
const rotated = await openemail.keys.rotate(key.id)
await openemail.keys.revoke(key.id, { reason: 'Replaced' })
await openemail.keys.delete(key.id)
```

`create` and `rotate` are the only calls that return a secret, in `token`, once. Every read returns `maskedKey` instead. `update` switches a key off and on with `enabled`, which is the reversible alternative to `revoke`, and `delete` only removes a key that has been revoked. Reading needs `keys:read` and every change needs `keys:manage`.

## Never wider than the caller

A key never makes or reaches a key wider than itself: scopes, role, expiry, mode and send scope all have to sit inside the calling key, or the call is refused with 403 `beyond_caller_authority`. A key narrowed to some domains or addresses only sees the keys inside its own send scope. `rotate` on the calling key also works with `keys:write`, like `me.rotate()`.

> Step-up verification cannot apply to a call made with a key, so `keys:manage` is a credential that makes credentials. Give it only to automation that provisions keys, give that key a role, a send scope and an expiry, and watch `listWorkspaceActivity`, where everything it does is recorded against it.

## Request log and activity

**key-logs.ts**

```
const failures = await openemail.keys.listRequests('4c1b257a66287fd113bd89d0', {
  failedOnly: true,
  since: new Date(Date.now() - 24 * 60 * 60 * 1000),
})

for await (const change of openemail.keys.iterateWorkspaceActivity()) {
  console.log(change.keyName, change.type, change.actor?.label)
}
```

`listRequests` and `listActivity` read one key, `listWorkspaceRequests` and `listWorkspaceActivity` read every key or the ones `keyIds` names, and each has a `listAll…` and an `iterate…` beside it. They take `since` and `until`, and the request readers also take `failedOnly`.
