Skip to main content
Send a permission query in the permissions field of keys.verifyKey to check that a key has the permissions a request needs. A query combines permission slugs with AND, OR, and parentheses. If the key’s permissions (its own plus its roles’) don’t satisfy it, verification fails with code: INSUFFICIENT_PERMISSIONS and no rate limit or credits are used.

Grammar

A PERMISSION is a slug made of letters, digits, ., _, -, :, *, and /. AND and OR can be any case. AND is evaluated before OR, as in SQL, and parentheses change that. The whole query can be up to 1000 characters.

Matching is exact

Each slug in the query must match one of the key’s permissions exactly, including case. There are no wildcards: a key with documents.* does not pass a query for documents.read. A query for documents.* only passes for a key that has a permission literally named documents.*.
Case matters when you query but not when you attach. If a permission is stored as Documents.Read, attaching documents.read finds it and attaches it, but a query for documents.read fails. Pick one casing and use it everywhere.
To grant a family of permissions, attach them to a role and assign the role. See Roles and permissions.

Outcomes and errors

Checking in your own code

When the decision needs data Unkey doesn’t have, verify without a query and read data.permissions:
authorize.ts
You can combine both: send a query for the part Unkey can decide, and use the returned list for the rest.
Last modified on September 29, 2026