Skip to main content
A recoverable key is one you can show again after it’s created. By default Unkey keeps only a hash of each key, so once keys.createKey returns it, nobody (including Unkey) can read it again. That’s the safest setup and right for most apps: a user who loses a key gets a new one. Use recoverable keys when showing a key again is worth the extra risk, such as an API playground that needs a working key, or a settings page where users expect to reveal their key. We store an encrypted copy and decrypt it only when you ask. Key storage explains how that copy is protected.

Opt the keyspace in

Recoverable keys need the keyspace’s Store encrypted keys setting. It’s off for new keyspaces and there’s no dashboard toggle, so email support with the keyspace’s API ID and we’ll turn it on. Keys created before that can’t be recovered.
You need a root key with the permissions listed on this page. Create one in the dashboard under Settings > Root Keys, and pass it as Authorization: Bearer <root key>. See Permission reference for every permission.
Creating a recoverable key needs api.*.encrypt_key or api.<api_id>.encrypt_key in addition to the create permission. Reading one back needs api.*.decrypt_key or api.<api_id>.decrypt_key in addition to the read permission. Grant these only to root keys that need them. See Root key permissions. A missing encrypt permission doesn’t look like a permission problem. keys.createKey returns HTTP 404 err:unkey:data:api_not_found, “The specified API was not found.” If you see this for an API ID you know is correct, check the root key’s encrypt_key permission first.

Create a recoverable key

boolean
default:"false"
On keys.createKey. When true, an encrypted copy of the key is stored. Fails with HTTP 412 err:unkey:application:precondition_failed when the keyspace doesn’t store encrypted keys (“This API does not support key encryption.”), and with HTTP 404 err:unkey:data:api_not_found when the root key lacks encrypt_key.
Rerolling a recoverable key produces a recoverable key, so the reroll needs the encrypt permission too.

Read the plaintext back

Both keys.getKey and apis.listKeys accept decrypt.
boolean
default:"false"
When true, every returned key that’s recoverable has a plaintext field. Other keys come back without it, and the request doesn’t fail.
decrypt: true fails with HTTP 412 when the key’s keyspace doesn’t store encrypted keys, and with a permission error when the root key lacks decrypt_key. Treat any response with plaintext like the original create response: send it over a secure channel, and never log or cache it.

Recoverable keys and rotation

If a key may have leaked, reroll it. Being able to read it again doesn’t make it safe. See Rerolling keys.
Last modified on September 29, 2026