---
title: "Encryption"
description: "Every operation in this group: what it accepts, what it returns and the errors it can answer with."
url: "https://openemail.uk/docs/api/reference/encryption"
area: "API"
category: "Reference"
---

# Encryption

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

## Operations

The OpenPGP public keys that let senders seal mail to an address, the directory the Encryption page of the app publishes to. Only public keys travel here: the private key stays on the device that made it, so nothing in this API can read sealed mail.

Published keys belong to a person. A key reads and publishes the keys of the workspace owner, and an app those of the person who connected it.

### `GET /encryption/keys`

List your published keys

Every key published for an address in this workspace, newest first, retired ones included with `revokedAt` and `revokedReason`. Published keys belong to a person. A key reads and publishes the keys of the workspace owner, and an app those of the person who connected it. A key limited to particular addresses lists only the keys of those addresses.

Requires the `emails:read` scope.

- Scopes: `emails:read`.

**Returns**

- `200` `EncryptionKeyList`: The keys, newest first.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: SDK [`encryption.listKeys()`](https://openemail.uk/docs/sdk/reference/encryption#listKeys); CLI [`openemail encryption list-keys`](https://openemail.uk/docs/cli/reference/encryption#encryption-list-keys); MCP [`listEncryptionKeys`](https://openemail.uk/docs/mcp/tools/encryption#listEncryptionKeys).

### `POST /encryption/keys`

Publish a public key for an address

Publishes an armored OpenPGP public key for one of your addresses, so that senders can seal mail to it, as Publish on the Encryption page does. The address has to be an address of this workspace on a verified domain, switched on, and one you may use.

An address keeps one live key. Publishing another while one is live is a 409 `key_already_published`; to rotate, send the fingerprint of the live key in `replaces`, and it is retired as the new one is published. Mail already sealed to the old key stays readable only with the old private key.

Published keys belong to a person. A key reads and publishes the keys of the workspace owner, and an app those of the person who connected it.

Requires the `emails:read` scope.

- Scopes: `emails:read`.
- Asks an OAuth access token for a verification code.

**Request body**

- `address` (`string`, required, up to 320 characters): The address the key is for.
- `publicKey` (`string`, required, 64 to 65536 characters, pattern `^-----BEGIN PGP PUBLIC KEY BLOCK-----[\s\S]+-----END PGP PUBLIC KEY BLOCK-----\s*$`): The armored OpenPGP PUBLIC KEY BLOCK, up to 64 KB.
- `fingerprint` (`string`, required, pattern `^[0-9A-F]{40}$`): The fingerprint of the key, 40 upper-case hexadecimal characters.
- `algorithm` (`string`, up to 32 characters): The algorithm of the key, such as `ed25519`, for display only.
- `replaces` (`string`, pattern `^[0-9A-F]{40}$`): The fingerprint of the live key this one replaces, to rotate it.

**Returns**

- `201` `EncryptionKey`: The key, now published.

**Errors**

- `403`: The key lacks the scope, or may not send as that address. `step_up_required`: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code with `POST /security/step-up`, send it to `POST /security/step-up/verify`, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
- `409`: `key_already_published`: the address has a live key and `replaces` was not given, or this key was published for it before. `domain_not_verified`: the domain of the address is not verified yet.
- The errors every operation can return: `400`, `401`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: SDK [`encryption.publishKey()`](https://openemail.uk/docs/sdk/reference/encryption#publishKey); CLI [`openemail encryption publish-key`](https://openemail.uk/docs/cli/reference/encryption#encryption-publish-key); MCP [`publishEncryptionKey`](https://openemail.uk/docs/mcp/tools/encryption#publishEncryptionKey).

### `GET /encryption/keys/lookup`

Find the keys to seal mail to

The live public keys published for each address, the lookup the composer makes before it seals a message. An address with no key comes back with `keys` empty, so mail to it cannot be sealed. Only keys published by somebody who can read the address count, so a key a former member left behind is never offered.

Requires the `emails:send` scope.

- Scopes: `emails:send`.

**Query parameters**

- `addresses` (`string`, required): Comma-separated recipient addresses, at most 51. A display name in angle brackets is read as its address.

**Returns**

- `200` `AddressKeysList`: One row per address asked about.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `500`, described in the [error catalog](https://openemail.uk/docs/api/errors).

Also available in: SDK [`encryption.lookupKeys()`](https://openemail.uk/docs/sdk/reference/encryption#lookupKeys); CLI [`openemail encryption lookup-keys`](https://openemail.uk/docs/cli/reference/encryption#encryption-lookup-keys); MCP [`lookupEncryptionKeys`](https://openemail.uk/docs/mcp/tools/encryption#lookupEncryptionKeys).

### Objects

#### `AddressKeys`

`object`

- `object` (`string`, required, one of `"address_keys"`)
- `address` (`string`, required): The address as it was read, lower-cased.
- `keys` (`object[]`, required)
  - `fingerprint` (`string`, required)
  - `publicKey` (`string`, required)
  - `createdAt` (`string`, required, format `date-time`)

#### `AddressKeysList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AddressKeys[]`)

#### `EncryptionKey`

`object`

- `object` (`string`, required, one of `"encryption_key"`)
- `id` (`string`, required): `pgpk_` and 24 hex.
- `address` (`string`, required)
- `fingerprint` (`string`, required): 40 upper-case hexadecimal characters.
- `publicKey` (`string`, required): The armored OpenPGP PUBLIC KEY BLOCK.
- `algorithm` (`string`, required)
- `createdAt` (`string`, required, format `date-time`)
- `revokedAt` (`string`, required, nullable, format `date-time`): When it was retired. Null on the live key.
- `revokedReason` (`string`, required, nullable)

#### `EncryptionKeyList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`EncryptionKey[]`)
