Claves API
`keys.list`, `list_all`, `iterate`, `get`, `create`, `update`, `delete`, `rotate` y `revoke`, y los lectores del registro de solicitudes y de la actividad.
Todos los métodos
from pathlib import Path from openemail import openemail key = openemail.keys.create({ 'name': 'Billing sender', 'scopes': ['emails:send'], 'domainAllowlist': ['billing.acme.com'], 'expiresInMinutes': 60 * 24 * 90,}) secret = Path('.openemail-billing-key')secret.touch(mode=0o600)secret.write_text(key['token']) openemail.keys.update(key['id'], {'enabled': False}) rotated = openemail.keys.rotate(key['id'])secret.write_text(rotated['token']) openemail.keys.revoke(key['id'], {'reason': 'Replaced'})openemail.keys.delete(key['id'])create y rotate son las únicas llamadas que devuelven un secreto, en token, una vez. Cada lectura devuelve maskedKey en su lugar. update desactiva y activa una clave con enabled, la alternativa reversible a revoke, y delete solo quita una clave que ya se revocó. Leer necesita keys:read y cada cambio keys:manage.
El cliente nunca reintenta create ni rotate. Un reintento tras una respuesta perdida crearía una segunda clave, o invalidaría el secreto que devolvió el primer intento. update y revoke se reintentan como las lecturas, porque repetirlos deja la misma clave, y delete no.
Nunca más amplia que quien llama
Una clave nunca crea ni alcanza una clave más amplia que ella misma: ámbitos, rol, caducidad, modo y ámbito de envío tienen que quedar dentro de la clave que llama, o la llamada se rechaza con 403 beyond_caller_authority. Una clave acotada a algunos dominios o direcciones solo ve las claves dentro de su propio ámbito de envío. rotate sobre la clave que llama también funciona con keys:write, como me.rotate().
La verificación adicional no puede aplicarse a una llamada hecha con una clave, así que keys:manage es una credencial que crea credenciales. Dala solo a una automatización que emite claves, dale a esa clave un rol, un ámbito de envío y una caducidad, y vigila list_workspace_activity, donde todo lo que hace queda registrado a su nombre.
Registro de solicitudes y actividad
from datetime import datetime, timedelta, timezone from openemail import openemail failures = openemail.keys.list_requests( '4c1b257a66287fd113bd89d0', failed_only=True, since=datetime.now(timezone.utc) - timedelta(days=1),)for request in failures['items']: print(request['status'], request['method'], request['path']) for change in openemail.keys.iterate_workspace_activity(): actor = change['actor'] print(change['keyName'], change['type'], actor['label'] if actor else None)list_requests y list_activity leen una clave, list_workspace_requests y list_workspace_activity leen todas las claves o las que nombra key_ids, y cada una tiene un list_all_… y un iterate_… al lado. Aceptan since y until, y los lectores de solicitudes aceptan además failed_only.
since y until aceptan un datetime o una cadena ISO 8601. Un datetime se envía en UTC, y uno sin zona horaria se interpreta antes como hora local.
Referencia
keys.list()Referencia completakeys.list_all()Referencia completakeys.iterate()Referencia completakeys.get()Referencia completakeys.create()Referencia completakeys.update()Referencia completakeys.delete()Referencia completakeys.rotate()Referencia completakeys.revoke()Referencia completakeys.list_requests()Referencia completakeys.list_all_requests()Referencia completakeys.iterate_requests()Referencia completakeys.list_activity()Referencia completakeys.list_all_activity()Referencia completakeys.iterate_activity()Referencia completakeys.list_workspace_requests()Referencia completakeys.list_all_workspace_requests()Referencia completakeys.iterate_workspace_requests()Referencia completakeys.list_workspace_activity()Referencia completakeys.list_all_workspace_activity()Referencia completakeys.iterate_workspace_activity()Referencia completa