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

# API keys

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

## Every method

**keys.rb**

```
key = client.keys.create(
  name: "Billing sender",
  scopes: ["emails:send"],
  domainAllowlist: ["billing.acme.com"],
  expiresInMinutes: 60 * 24 * 90
)

File.write(".openemail-billing-key", key[:token])

client.keys.update(key[:id], enabled: false)

rotated = client.keys.rotate(key[:id])
File.write(".openemail-billing-key", rotated[:token])

client.keys.revoke(key[:id], reason: "Replaced")
client.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: any other key is a 409 `not_revoked`. Reading needs `keys:read` and every change needs `keys:manage`.

> The gem never retries `create` or `rotate`. A retry after a lost response would mint a second key, or invalidate the secret the first attempt returned. `update` and `revoke` are retried after a network failure, because repeating them leaves the same key, and `delete` is not.

## 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 raises `OpenEmail::PermissionError` with the code `beyond_caller_authority`, and `param` names the axis. 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 `client.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 `list_workspace_activity`, where everything it does is recorded against it.

## Request log and activity

**key_logs.rb**

```
failures = client.keys.list_requests(
  "4c1b257a66287fd113bd89d0",
  failed_only: true,
  since: Time.now - (24 * 60 * 60)
)
puts failures.items.size

client.keys.iterate_workspace_activity do |change|
  puts [change[:keyName], change[:type], change.dig(:actor, :label)].join(" ")
end
```

`list_requests` and `list_activity` read one key, and `list_workspace_requests` and `list_workspace_activity` read every key or the ones `key_ids:` names. Each has a `list_all_` and an `iterate_` twin beside it, such as `list_all_requests` and `iterate_requests`. They take `since:` and `until:` as a `Time`, a `DateTime` or an ISO 8601 string, and the request readers also take `failed_only:`.

> `until` is a reserved word in Ruby, but `until:` works as a keyword argument as written. It has to be later than `since:`, or the call raises `OpenEmail::InvalidRequestError` with the code `invalid_parameter`.
