API keys
`keys.list`, `listAll`, `iterate`, `get`, `create`, `update`, `delete`, `rotate` and `revoke`, and the request log and activity readers.
Every method
const key = await nextmail.keys.create({ name: 'Billing sender', scopes: ['emails:send'], domainAllowlist: ['billing.acme.com'], expiresInMinutes: 60 * 24 * 90,}) await store(key.token) await nextmail.keys.update(key.id, { enabled: false })const rotated = await nextmail.keys.rotate(key.id)await nextmail.keys.revoke(key.id, { reason: 'Replaced' })await nextmail.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
const failures = await nextmail.keys.listRequests('4c1b257a66287fd113bd89d0', { failedOnly: true, since: new Date(Date.now() - 24 * 60 * 60 * 1000),}) for await (const change of nextmail.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, statuses and path.
statuses keeps the calls answered with those exact status codes, and path keeps the calls to one route, whatever the method. path matches the route, not the exact path: an id counts as :id and an email address as :address, so /emails/:id reads the calls made to any single email, and a path that ends in * reads every route that starts with it.
A key reads its own log with no scope at all. me.listRequests, me.listActivity and me.stats answer for the calling key and no other, so a key that can only send can still watch itself. me.stats fills sends only when the key holds emails:read.
Google Workspace