Create an API key
Creates an API key and returns the generated credential string and key metadata. The full secret credential is returned only in this response because credentials are stored only as hashes. A lost credential cannot be recovered and must be replaced. Server logs record the key id, never the credential value.
When a key is created, roles are expanded into their constituent permissions. Only the resulting permissions are stored in the key. Existing keys do not change permissions if role definitions change in later software versions.
A key created on one node works on all nodes immediately because nodes look up unseen keys without delay. Served by whichever node receives the request.
Body
What a key should be allowed to do. See Permissions.
descriptionstring"the search backend"grantsGrantDefinition[]requiredExample
{ "role": "reader", "indexes": [ "products" ]}3 properties
rolestringreader grants search and indexes.read. writer adds documents.read, documents.write, documents.delete, and indexes.commit, but not indexes.write. admin grants all permissions, including key management. When a key is created, roles are expanded into their constituent permissions. Only the resulting permissions are stored in the key. Existing keys do not change permissions if role definitions change in later software versions.- Values
- "reader", "writer", "admin"
"reader"permissionsstring[]role specifies. An unknown permission name returns auth:key:permission_unknown.indexesstring[]*; a single * matches all indexes. Required for index-scoped permissions and ignored for deployment-scoped permissions. Generations are named index@generation: products matches the index but no generation of it, products@* matches every generation but not the index itself, and products* matches both.expiresAtstring"2027-01-01T00:00:00Z"Responses
credential in this response is the only copy returned.CreatedKey
A newly created key. This is the only response its credential ever appears in.
credentialstringAuthorization: Bearer. Only a hash of it is stored, so this response is the only chance to keep it. A lost credential cannot be recovered and must be replaced."exok_4ff6b760264c1918_ePQcdT1O9HSATZoXfDbT8hhHGsP9VpZH"keyKeyInfoExample
{ "id": "4ff6b760264c1918", "description": "the search backend", "grants": [ { "permissions": [ "indexes.read", "search" ], "indexes": [ "products" ] } ], "createdAt": "2026-08-16T12:09:33.198275Z", "expiresAt": "2027-01-01T00:00:00Z"}5 properties
idstring"4ff6b760264c1918"descriptionstring"the search backend"grantsGrant[]Example
{ "permissions": [ "indexes.read", "search" ], "indexes": [ "products" ]}2 properties
permissionsstring[]indexesstring[]createdAtstring"2026-08-16T12:09:33.198275Z"expiresAtstringnull for a key that does not expire."2027-01-01T00:00:00Z"ErrorResponse
The body of every failed request. Error codes use colon-separated namespaces such as index:field:name_invalid, are stable across API versions, and are never renamed or reused, so clients match on code rather than on message. See Errors.
codestringvalidation and the individual problems are listed in errors. For all other failures, this matches the code of the single entry in errors."validation"messagestringcode rather than on message. When a validation failure contains one problem, this is that problem's message. When it contains several, it reads Request contains N errors."Request contains 2 errors"errorsErrorDetail[]Example
{ "code": "index:field:primary_key:multiple_unsupported", "message": "Field `id` is marked as a primary key and multiple, primary keys can not have multiple values", "path": "id"}4 properties
codestring"index:field:primary_key:multiple_unsupported"messagestring"Field `id` is marked as a primary key and multiple, primary keys can not have multiple values"pathstringfields.title or documents[1].nonexistent. Names join with ., one element of a list reads [n] counted from zero, and a key of a free-form map such as metadata goes in brackets and double quotes when it holds a dot or a bracket, as metadata["build.sha"]. A field inside an object field carries its own dotted path, so a path here reaches a field the same way a query does. Omitted when the problem applies to the request as a whole. See API conventions."id"argumentsmap of string1 property
<key>stringError codes
- request:body_required
- The request carries no body.
- auth:key:role_unknown
- The definition names a role this version does not have.
- auth:key:permission_unknown
- The definition names a permission this version does not have.
- auth:key:grants_required
- The definition holds no grant, so the key could do nothing.
- auth:key:permissions_required
- A grant names neither a role nor a list of permissions.
- auth:key:indexes_required
- A grant holds a permission that is about one index and does not say which indexes it covers.
- auth:key:index_pattern_invalid
- An entry of `indexes` is neither an index name nor a prefix followed by `*`.
- auth:key:indexes_unsupported
- A grant names `indexes` and holds no permission that is about one index, so the patterns would narrow nothing.
- auth:key:expiry_invalid
- `expiresAt` is not an ISO 8601 timestamp.
- auth:key:expiry_in_past
- `expiresAt` has already passed, so the key would be lapsed from the moment it was created.
WWW-Authenticate: Bearer.ErrorResponse
The body of every failed request. Error codes use colon-separated namespaces such as index:field:name_invalid, are stable across API versions, and are never renamed or reused, so clients match on code rather than on message. See Errors.
codestringvalidation and the individual problems are listed in errors. For all other failures, this matches the code of the single entry in errors."validation"messagestringcode rather than on message. When a validation failure contains one problem, this is that problem's message. When it contains several, it reads Request contains N errors."Request contains 2 errors"errorsErrorDetail[]Example
{ "code": "index:field:primary_key:multiple_unsupported", "message": "Field `id` is marked as a primary key and multiple, primary keys can not have multiple values", "path": "id"}4 properties
codestring"index:field:primary_key:multiple_unsupported"messagestring"Field `id` is marked as a primary key and multiple, primary keys can not have multiple values"pathstringfields.title or documents[1].nonexistent. Names join with ., one element of a list reads [n] counted from zero, and a key of a free-form map such as metadata goes in brackets and double quotes when it holds a dot or a bracket, as metadata["build.sha"]. A field inside an object field carries its own dotted path, so a path here reaches a field the same way a query does. Omitted when the problem applies to the request as a whole. See API conventions."id"argumentsmap of string1 property
<key>stringError codes
- auth:unauthenticated
- The request carries no credential this node accepts.
keys.write permission.ErrorResponse
The body of every failed request. Error codes use colon-separated namespaces such as index:field:name_invalid, are stable across API versions, and are never renamed or reused, so clients match on code rather than on message. See Errors.
codestringvalidation and the individual problems are listed in errors. For all other failures, this matches the code of the single entry in errors."validation"messagestringcode rather than on message. When a validation failure contains one problem, this is that problem's message. When it contains several, it reads Request contains N errors."Request contains 2 errors"errorsErrorDetail[]Example
{ "code": "index:field:primary_key:multiple_unsupported", "message": "Field `id` is marked as a primary key and multiple, primary keys can not have multiple values", "path": "id"}4 properties
codestring"index:field:primary_key:multiple_unsupported"messagestring"Field `id` is marked as a primary key and multiple, primary keys can not have multiple values"pathstringfields.title or documents[1].nonexistent. Names join with ., one element of a list reads [n] counted from zero, and a key of a free-form map such as metadata goes in brackets and double quotes when it holds a dot or a bracket, as metadata["build.sha"]. A field inside an object field carries its own dotted path, so a path here reaches a field the same way a query does. Omitted when the problem applies to the request as a whole. See API conventions."id"argumentsmap of string1 property
<key>stringError codes
- auth:forbidden
- The key is accepted but does not hold the `keys.write` permission.
ErrorResponse
The body of every failed request. Error codes use colon-separated namespaces such as index:field:name_invalid, are stable across API versions, and are never renamed or reused, so clients match on code rather than on message. See Errors.
codestringvalidation and the individual problems are listed in errors. For all other failures, this matches the code of the single entry in errors."validation"messagestringcode rather than on message. When a validation failure contains one problem, this is that problem's message. When it contains several, it reads Request contains N errors."Request contains 2 errors"errorsErrorDetail[]Example
{ "code": "index:field:primary_key:multiple_unsupported", "message": "Field `id` is marked as a primary key and multiple, primary keys can not have multiple values", "path": "id"}4 properties
codestring"index:field:primary_key:multiple_unsupported"messagestring"Field `id` is marked as a primary key and multiple, primary keys can not have multiple values"pathstringfields.title or documents[1].nonexistent. Names join with ., one element of a list reads [n] counted from zero, and a key of a free-form map such as metadata goes in brackets and double quotes when it holds a dot or a bracket, as metadata["build.sha"]. A field inside an object field carries its own dotted path, so a path here reaches a field the same way a query does. Omitted when the problem applies to the request as a whole. See API conventions."id"argumentsmap of string1 property
<key>stringError codes
- storage:unavailable
- The node is not configured with key storage.
- storage:io_error
- Key storage answered with an error. Send the request again.
- storage:conflict
- Other nodes kept changing the stored keys. The stored keys are unchanged; send the request again.
Authorization
- Permission
- keys.write
- Checked on
- The deployment, not one index
- Roles
admin
An API key sent as a bearer token, such as Authorization: Bearer exok_4ff6b760264c1918_ePQcdT1O9HSATZoXfDbT8hhHGsP9VpZH. A key carries grants that pair permissions with index patterns; the permission each endpoint needs is named beside it. Nodes running with EXOFIND_AUTH_MODE=none accept requests without a credential, and a node with EXOFIND_AUTH_ANONYMOUS_KEY set serves requests that carry none with the permissions of that key.
Exofind is built by Level Four AB and is available under the Apache License 2.0.