keys.createKey. The only required field is the keyspace’s API ID. Everything else is optional and you can change it later with keys.updateKey. You get the key back once, in the response.
Create a root key with the permissions listed on this page under Root Keys in the dashboard sidebar. CLI commands can instead use a session from unkey login with the required permissions. See Permission reference for every permission.
unkey:v1:<workspace_id>:projects/<project_id>/keyspaces/<keyspace_id>/keys/*#write for the target keyspace. Use the keyspace’s project ID. Recoverable keys use the same write permission and require the keyspace to support key encryption. Without write permission, you get HTTP 404 err:unkey:data:api_not_found, so a missing grant looks like a missing API. If the root key can read the keyspace, you get HTTP 403 err:unkey:authorization:insufficient_permissions naming the missing write permission instead. See Root key permissions.
Request fields
The keyspace that owns the key, by API ID (
api_...). 3 to 255 characters matching ^[a-zA-Z0-9_]+$. You can’t move a key to another keyspace later.1 to 16 characters matching
^[a-zA-Z0-9_]+$. Becomes the start of the key as <prefix>_<random>, so users can tell keys apart in logs. When omitted, the key uses the keyspace’s default prefix if one is set, and otherwise has no prefix. Don’t put secrets or customer names in a prefix. It’s visible wherever the key is.1 to 255 characters. An internal label returned by
keys.getKey, apis.listKeys, and keys.verifyKey. Unkey never shows it to your users.16 to 255 random bytes, base58-encoded into the key. When omitted, the key uses the keyspace’s default bytes value, or 16 if that’s unset. 16 bytes gives 2^128 possibilities, and 32 is plenty for the most sensitive uses.
1 to 255 characters matching
^[a-zA-Z0-9_.-]+$: your identifier for the user, organization, or tenant that owns the key. Unkey creates an identity with this externalId if none exists and links the key to it, so every verification returns identity.externalId and any metadata or shared rate limits set on the identity. See Identities.Arbitrary JSON returned in full on every verification. At most 100 top-level properties. Keep it small: it travels with every
keys.verifyKey response, and the whole request body is capped at 10 MiB. Don’t store secrets here. See Metadata and tags.Up to 100 role names, each 1 to 128 characters. Every role must already exist in the workspace or the request fails. Roles bundle permissions, and the key gains all of them.
Up to 1000 permission slugs, each 1 to 128 characters matching
^[a-zA-Z0-9_:\-\.\*]+$. Added to the key on top of what its roles grant. Unlike roles, a slug that doesn’t exist yet is created for you. An asterisk is a literal character, not a wildcard.Unix timestamp in milliseconds, at most
4102444800000 (1 January 2100). After this instant verification returns code: EXPIRED. Omit for a key that never expires. See Key expiration.Usage metering.
credits.remaining (integer, 0 or more) is the number of verifications the key can still afford. credits.refill optionally restores it on a schedule with interval (daily or monthly), amount (1 or more), and refillDay (1 to 31, required for monthly). remaining must be set whenever refill is set. Omit the whole object for unlimited usage. See Credits and refill.Up to 50 named rate limits, each with
name (3 to 128 characters), limit (1 or more), duration in milliseconds (1000 or more), and autoApply (boolean, required). Limits with autoApply: true are checked on every verification. The others are checked only when a verification names them. See Key and identity rate limits.Set to
false to create the key in a disabled state. Verification returns code: DISABLED until you enable it. See Disabling and deleting keys.Store an encrypted copy of the key so
keys.getKey and apis.listKeys can show it later with decrypt: true. If the keyspace doesn’t have encrypted storage turned on, you get HTTP 412 err:unkey:application:precondition_failed. If the root key lacks the encrypt permission, you get HTTP 404 err:unkey:data:api_not_found, or HTTP 403 naming the missing permission if it can read the keyspace. See Recoverable keys.Example
Response
keyId is the identifier you use for every later management call. key is the key itself, and this is the only time it’s returned. Unkey keeps only a hash, plus an encrypted copy if you asked for a recoverable key. Send it to your user over a secure channel and don’t log it.
Key format
A key looks like<prefix>_<random>, or just <random> without a prefix. The random part is byteLength random bytes in base58. keys.getKey and apis.listKeys return a start field, <prefix>_<first four characters>, so you can recognize a key without seeing all of it.
From the dashboard
The keyspace’s Create key dialog has the same fields in six steps: general setup, rate limits, credits, expiration, permissions, and metadata. Two things differ from the API. Expiry must be at least two minutes in the future, and the general step has an field, a free-text label of up to 256 characters. The API can’t set it and verification doesn’t return it, so usemeta if your backend needs the label.
