def create(
body: KeyCreate,
*,
timeout: float | None = None,
) -> CreatedKeyResourceasync def create(
body: KeyCreate,
*,
timeout: float | None = None,
) -> CreatedKeyResourceMints a key for the workspace and returns the only key shape that ever carries secret. The plaintext is handed over exactly once, only a hash is stored, and no endpoint or dashboard screen can produce it again. Write it to your secret store before you read anything else off the result. prefix is the leading portion of that secret and is safe to log.
Requested scopes pass through two independent reductions. First a ceiling: a key can never mint a key stronger than itself, and any resource:level above what the calling key holds rejects the whole request with 403 auth.scope_ceiling_exceeded while creating nothing. Whatever survives is then clamped silently to the workspace role of the calling key owner, so a requested write can land as read, or as none if the owner cannot read that resource at all. Read scopes back off the response rather than assuming you got what you asked for.
body['projectIds'] fences the key to specific projects and takes project ids, not slugs. Omit it or send an empty list for a workspace-wide key. If the calling key is itself fenced, the field becomes mandatory and must be a non empty subset of the caller own projects, otherwise the call fails with 403 auth.key_project_restricted.
Example
from pathlib import Path
from envless import envless
created = envless.keys.create(
{
'name': 'ci-deploy',
'scopes': {'variables': 'read', 'projects': 'read'},
}
)
Path('envless-ci-key').write_text(created['secret'])
print(created['prefix'], created['scopes'])import asyncio
from pathlib import Path
from envless import AsyncEnvless
async def main() -> None:
async with AsyncEnvless() as envless:
created = await envless.keys.create(
{
'name': 'ci-deploy',
'scopes': {'variables': 'read', 'projects': 'read'},
}
)
Path('envless-ci-key').write_text(created['secret'])
print(created['prefix'], created['scopes'])
asyncio.run(main())Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
body['name'] | str | Yes | Label for the key, 4 to 34 characters. |
body['scopes'] | dict[str, str] | No | Map of resource to none, read or write, where write implies read. |
body['projectIds'] | list[str] | No | Project ids the key is fenced to, empty or omitted for workspace-wide. |
timeout | float | No | Seconds each attempt of this call may take, the response body included, before it raises EnvlessNetworkError with is_timeout set. Overrides the client's timeout for this call, and 0 turns the limit off. |
Returns
CreatedKeyResource, a KeyResource plus the one time plaintext secret.
Worth knowing
- Omitting
scopesis legal and produces a key with every resource atnone. It authenticates but can call nothing exceptme.get. - There is no rotate method. To roll a credential, create the replacement, deploy it, wait until
lastUsedAton the old key stops advancing, then calldeleteon the old id. - A workspace is capped at 100 live keys and the next create rejects with 409
key.limit_reached.
Required scopes
keys:write
Underlying endpoint
POST /keys
Request and response schema, every error code, and a live playground.
In TypeScript
envless.keys.create()
The same method in @goenvless/sdk, with the same request, retries and errors.