---
title: "openemail.me"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://openemail.uk/docs/sdk/reference/me"
area: "SDK"
category: "Reference"
---

# openemail.me

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

The API key or OAuth access token behind the client: its mode, scopes, role ceiling and workspace.

### `me.get()`

Describe the API key or access token making the call

```ts
get(options?: RequestScope): Promise<KeyResource>
```

Returns what the key is: its id, whether it is a live or test key, the workspace it belongs to, the scopes it can use and the allowlists that narrow who it may send as. It needs no scope, because a key may always describe itself, so it works with any valid key and is the first call to make when a request is refused.

`scopes` is the effective list and the only one that authorises anything. It is the scopes the key was created with intersected with the permissions of the role it was issued under, resolved on every request rather than frozen into the key. `grantedScopes` is what the key was created holding and `roleId` names the role that capped it, so a scope present in `grantedScopes` and missing from `scopes` was removed by that role. A 403 `insufficient_scope` on a key the console shows as holding the scope is almost always this, and the fix is to change the role rather than to mint another key.

A key can be narrowed by whole domains, by individual addresses, or by both. `domainAllowlist` holds whole domains, and the key may send as any address on one of them, including addresses created after the key was. `addressAllowlist` holds individual addresses and covers only those. Both null means the key may send as any address the workspace owns. When either is set the key is narrowed, and reads of sent mail, tracking and calendar narrow to the same set. An address whose domain is already in `domainAllowlist` is dropped from `addressAllowlist` when the key is saved, so the two lists never overlap.

Called with an OAuth access token it describes the token instead, and `object` tells the two apart. A key answers `object: 'api_key'` and `kind: 'apiKey'`. A token answers `object: 'oauth_token'` and `kind: 'oauth'`, with `id` null, `clientId` naming the connected app, `roleId` null and `mode` always `live`. `scopes` and `grantedScopes` are the permissions the person approved for the app, and the allowlists are the addresses and domains the app may reach. `expiresAt` is when that approval runs out, or null when it never does. It is not the expiry of the access token, which the app renews with its refresh token.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Describes this key instead of the credential the client was built with.

**Returns**

`KeyResource`. For an API key it is `ApiKeySelfResource`, with `object` set to `api_key`, `kind`, `id`, `mode`, `scopes`, `grantedScopes`, `roleId`, `workspaceId`, `addressAllowlist` and `domainAllowlist`. For an OAuth access token it is `OauthTokenSelfResource`, with `object` set to `oauth_token`, the same fields with `id` and `roleId` null, plus `clientId` and `expiresAt`.

**Example**

```ts
const key = await openemail.me.get()

console.log(key.mode, key.workspaceId)

const removedByRole = key.grantedScopes.filter((scope) => !key.scopes.includes(scope))

console.log(removedByRole)

if (key.object === 'oauth_token') console.log(key.clientId, key.expiresAt)
```

**Notes**

- Narrowing a role takes effect on the next request without touching the key itself, so `scopes` can shrink between two calls with the same secret. Replacing the secret is a separate act, and `me.rotate` is the call that does it.
- `roleId` is null on a key with no ceiling, which is what every key issued before roles existed still has.
- A failure here is a 401 naming the credential problem: `missing_api_key`, `invalid_api_key`, `revoked_api_key`, `expired_api_key` or `inactive_api_key` for a key switched off in the console.
- An access token that has run out is a 401 `expired_access_token`, which the app answers by renewing it with its refresh token. `invalid_access_token` and the `grant_*` codes mean the app has to be connected again.

Also available in: API [`GET /keys/self`](https://openemail.uk/docs/api/reference/account#get-keys-self); CLI [`openemail me get`](https://openemail.uk/docs/cli/reference/me#me-get).

### `me.ping()`

Check that a key or access token authenticates

```ts
ping(options?: RequestScope): Promise<PingResource>
```

An authentication smoke test. It runs the same key check every other endpoint runs and answers `ok: true` with the key id, its mode, the workspace and the effective scopes. It needs no scope, so a key with none at all still gets a 200.

Use it in a health check or at process start to fail fast on a revoked, expired or mistyped key. The answer carries the same scope detail as `me.get`, `scopes` effective and `grantedScopes` as created with `roleId` naming the cap between them, but it leaves out both allowlists. Call `me.get` when you need to know which domains and which addresses the key may send as.

An OAuth access token gets the same answer with `kind: 'oauth'`, `keyId` null, `clientId` naming the connected app, `roleId` null and `mode` always `live`. A key answers `kind: 'apiKey'`.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Checks this key instead of the credential the client was built with.

**Returns**

`PingResource` with `ok` set to true, `kind`, `keyId`, `mode`, `scopes`, `grantedScopes`, `roleId` and `workspaceId`, plus `clientId` for an OAuth access token.

**Example**

```ts
const ping = await openemail.me.ping()

if (!ping.scopes.includes('emails:send')) {
    throw new Error(`Key ${ping.keyId} cannot send mail`)
}
```

**Notes**

- The id is `keyId` here and `id` on `me.get`, and there is no `object` field on this response, so tell a key from a token by `kind`.
- A bad key never resolves with `ok: false`. It throws an `OpenEmailApiError` with status 401, so `isAuth` is the check to make.

Also available in: API [`GET /ping`](https://openemail.uk/docs/api/reference/account#get-ping); CLI [`openemail me ping`](https://openemail.uk/docs/cli/reference/me#me-ping).

### `me.rotate()`

Replace the calling key's own secret

```ts
rotate(options?: RequestScope): Promise<RotatedKeyResource>
```

Mints a new secret for the key making the call and resolves with the same body as `me.get` plus `token`, the new key in full. That is the only place the value appears, so store it before anything else.

Everything else about the key survives. The id, the mode, the scopes, the role ceiling, the address allowlist and the domain allowlist all come back unchanged, so `token` is the only thing your configuration has to change. Because the id is stable, an audit trail joined on it stays joined up across rotations.

There is no overlap window. The old secret stops authenticating the moment this call commits, and neither secret can be shown again. Write `token` to wherever the key is read from before the next request. A lost response is the bad case: the rotation may have committed to a secret nobody saw, which leaves the key unusable until someone mints it a new secret in the console.

Scopes: `keys:write`.

**Parameters**

- `options.signal` (`AbortSignal`): Cancels the request.
- `options.apiKey` (`string`): Rotates this key instead of the one the client was built with.

**Returns**

`RotatedKeyResource`: the `KeyResource` body plus `token`, the new key formatted `oe_live_` or `oe_test_` then the 24 character key id, an underscore and 43 base64url characters, plus `rotationCount` and `rotatedAt`.

**Example**

```ts
const rotated = await openemail.me.rotate()

console.log(rotated.rotationCount, rotated.rotatedAt)

const check = await openemail.me.get({ apiKey: rotated.token })

console.log(check.id, check.scopes)
```

**Notes**

- It needs `keys:write`, and a key without it gets 403 `insufficient_scope`. No key holds that scope unless somebody gave it one in the console, so a key that cannot reach this call has to be rotated from there.
- There is no request body and the success status is 200, not 201.
- Not retried automatically. Repeating a rotation would invalidate the secret the first attempt returned, so a failure has to be judged rather than retried.
- The 404 and the two 409s are races rather than everyday answers, because a key that is missing, revoked or expired cannot authenticate this call in the first place. They mean the key changed state between authenticating and rotating: 404 if the row went, 409 `revoked` or 409 `expired` otherwise. None of the three is rotatable, so the answer is a new key from the console.
- `rotationCount` is the count after this call, so the first rotation of a key answers 1, and `rotatedAt` is when that rotation committed.

Also available in: API [`POST /keys/self/rotate`](https://openemail.uk/docs/api/reference/account#post-keys-self-rotate); CLI [`openemail me rotate`](https://openemail.uk/docs/cli/reference/me#me-rotate).
