Skip to the documentation
SDK

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.