Create API keys for Elastic Agent Builder
Use an API key to authenticate applications that call Elastic Agent Builder programmatically, including custom clients, scripts that use curl, MCP clients, and A2A clients.
API keys use the same Kibana feature privileges as roles. The role management UI displays names such as Agent Builder: Read, while an API key role descriptor uses the corresponding application privilege name, such as feature_agentBuilder.read.
Before creating an API key:
Make sure the user creating the key has the
manage_api_keyormanage_own_api_keycluster privilege.Create the key as a user, not by authenticating the request with another API key. An API key can create only a derived key with no privileges.
Make sure the user creating the key has every privilege that you assign to the key. An API key cannot grant more privileges than its owner has.
Identify the Kibana space that the client will access. The examples use the default space.
Identify the index patterns that agents and tools need to query. Replace
customer-*in the examples with your own patterns.Determine whether agents use Elasticsearch inference endpoints, Kibana connectors, or workflows. These features require additional privileges.
Refer to the privilege reference for the exact privilege names to use in a role descriptor.
After you create the key, copy and securely store its
encodedvalue. You cannot retrieve it later.If you're using
curl, set the Elasticsearch URL, Kibana URL, and username:export ELASTICSEARCH_URL="https://<elasticsearch-host>" export KIBANA_URL="https://<kibana-host>" export ELASTIC_USERNAME="<username>"- Use
ELASTICSEARCH_URLto create API keys with the Elasticsearch/_security/api_keyAPI. To locate it, refer to Find your Elasticsearch endpoint. - Use
KIBANA_URLto call the Elastic Agent Builder APIs under/api/agent_builder. ELASTIC_USERNAMEis the username of the user creating the key. Thecurlexamples prompt you for this user's password.
- Use
The curl examples authenticate directly to Elasticsearch with a username and password. Serverless does not support this authentication method, so create the key in Console or the API keys UI instead.
The following example creates a key for a client that can use agents and view Elastic Agent Builder components, but cannot create, update, or delete them. The key can read data only from indices matching customer-*.
Run the following request in Console. The key is owned by the user who is signed in to Kibana:
POST /_security/api_key
{
"name": "agent-builder-read-only",
"expiration": "30d",
"role_descriptors": {
"agent-builder-read-only": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.read",
"feature_actions.read",
"feature_workflowsManagement.read"
],
"resources": ["space:default"]
}
]
}
}
}
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.readprovides read-only access to Elastic Agent Builder. The other two privileges provide read-only access to connectors and workflows.- Replace
space:defaultif the client uses a different Kibana space.
The command prompts for the password associated with ELASTIC_USERNAME.
curl --user "${ELASTIC_USERNAME}" \
-X POST "${ELASTICSEARCH_URL}/_security/api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "agent-builder-read-only",
"expiration": "30d",
"role_descriptors": {
"agent-builder-read-only": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.read",
"feature_actions.read",
"feature_workflowsManagement.read"
],
"resources": ["space:default"]
}
]
}
}
}'
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.readprovides read-only access to Elastic Agent Builder. The other two privileges provide read-only access to connectors and workflows.- Replace
space:defaultif the client uses a different Kibana space.
- Go to the API keys management page in the navigation menu or use the global search field, then select Create API key.
- Enter a name and expiration for the key.
- Enable Control security privileges.
- Paste the following role descriptor into the editor, then create the key:
{
"agent-builder-read-only": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.read",
"feature_actions.read",
"feature_workflowsManagement.read"
],
"resources": ["space:default"]
}
]
}
}
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.readprovides read-only access to Elastic Agent Builder. The other two privileges provide read-only access to connectors and workflows.- Replace
space:defaultif the client uses a different Kibana space.
Remove privileges that the client does not need:
- Remove
feature_actions.readif agents do not use Kibana connectors. - Remove
feature_workflowsManagement.readif agents do not interact with workflows. - Add
feature_workflowsManagement.workflow_executeif any agent uses a workflow tool. Read access lets an agent reference a workflow; running one requires the execute privilege. - Remove
monitor_inferenceif agents and tools do not call the Elasticsearch Inference API.
This example allows a client to manage Elastic Agent Builder components and workflows while keeping index access read-only.
feature_agentBuilder.all also grants skills management.
POST /_security/api_key
{
"name": "agent-builder-management",
"expiration": "30d",
"role_descriptors": {
"agent-builder-management": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.all",
"feature_actions.read",
"feature_workflowsManagement.all"
],
"resources": ["space:default"]
}
]
}
}
}
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.allallows the client to manage Elastic Agent Builder components.feature_actions.readallows it to use connectors, andfeature_workflowsManagement.allallows it to manage workflows.- Replace
space:defaultif the client uses a different Kibana space.
The command prompts for the password associated with ELASTIC_USERNAME.
curl --user "${ELASTIC_USERNAME}" \
-X POST "${ELASTICSEARCH_URL}/_security/api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "agent-builder-management",
"expiration": "30d",
"role_descriptors": {
"agent-builder-management": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.all",
"feature_actions.read",
"feature_workflowsManagement.all"
],
"resources": ["space:default"]
}
]
}
}
}'
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.allallows the client to manage Elastic Agent Builder components.feature_actions.readallows it to use connectors, andfeature_workflowsManagement.allallows it to manage workflows.- Replace
space:defaultif the client uses a different Kibana space.
Enable Control security privileges and paste the following role descriptor into the editor:
{
"agent-builder-management": {
"cluster": ["monitor_inference"],
"indices": [
{
"names": ["customer-*"],
"privileges": ["read", "view_index_metadata"]
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"feature_agentBuilder.all",
"feature_actions.read",
"feature_workflowsManagement.all"
],
"resources": ["space:default"]
}
]
}
}
monitor_inferenceis required when agents or tools call the Elasticsearch Inference API. Remove it if they do not.- Replace
customer-*with the index patterns that the client needs. The assigned index privileges allow reads and access to index mappings, but not writes. - Use
kibana-.kibanaas the application name for Kibana feature privileges. feature_agentBuilder.allallows the client to manage Elastic Agent Builder components.feature_actions.readallows it to use connectors, andfeature_workflowsManagement.allallows it to manage workflows.- Replace
space:defaultif the client uses a different Kibana space.
The feature_agentBuilder.all application privilege does not grant write access to indices. Tools continue to run with only the read and view_index_metadata index privileges assigned to the key.
An unrestricted key can access everything its owner can access. Use this approach only for development or trusted administrative automation. Before using a key in production, replace it with a restricted key that grants only the required spaces, indices, and features.
For short-lived development or administrative automation, you can create a key without role descriptors:
POST /_security/api_key
{
"name": "agent-builder-development",
"expiration": "1d"
}
The command prompts for the password associated with ELASTIC_USERNAME.
curl --user "${ELASTIC_USERNAME}" \
-X POST "${ELASTICSEARCH_URL}/_security/api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "agent-builder-development",
"expiration": "1d"
}'
Enter a name and expiration for the key, leave Control security privileges disabled, and create the key.
The key inherits a point-in-time snapshot of the privileges of the user who creates it. It is an administrator key only when the owner has administrator privileges.
If troubleshooting shows that a key is missing privileges, update it instead of creating another key:
- In Kibana, go to the API keys management page in the navigation menu or use the global search field. Click the key name, update Control security privileges, and save your changes.
- To use the Elasticsearch API, send
PUT /_security/api_key/<api-key-id>with the complete updatedrole_descriptorsobject. Authenticate as the user who owns the key; API key credentials cannot authenticate this request. The user needs at least themanage_own_api_keycluster privilege.
When you include role_descriptors, the update replaces the key's assigned role descriptors instead of merging the changes. Include every privilege that the key must retain. Do not submit an empty role_descriptors object, because the key would inherit all privileges of its owner.
Expired or invalidated keys cannot be updated. To learn about updating a key's expiration or metadata, refer to Update an API key and the update API key API.
Use the encoded value of the API key to authenticate requests to the Elastic Agent Builder APIs. The request URL depends on the Kibana space that the key can access.
Store the encoded value securely, set it as an environment variable, and send it in the Authorization header:
export API_KEY="<encoded-api-key>"
curl -X GET "${KIBANA_URL}/api/agent_builder/tools" \
-H "Authorization: ApiKey ${API_KEY}"
- Use the
encodedvalue returned when you created the API key, not the separateidorapi_keyvalues.
When you create a key for a custom space, set the role descriptor's application privilege resource to that space. For a key with "resources": ["space:production"], use the same space identifier in the request URL. To change an existing key's space access, update the key.
curl -X GET "${KIBANA_URL}/s/production/api/agent_builder/tools" \
-H "Authorization: ApiKey ${API_KEY}"
- The
productionspace in the URL must matchspace:productionin the key's role descriptor.
The following list pairs common API key symptoms with checks or changes that can resolve them. If a key is missing privileges, update its role descriptors.
401 Unauthorized- Make sure the header uses the
encodedvalue returned by the create API, not the separateidorapi_keyfields. 403 Forbidden- Check that the key has the required Kibana application privileges and that the space in the URL matches the
resourcesvalue. Also make sure the key owner has the privileges assigned to the key. If privileges are missing, update the key. - An agent or tool cannot find data
- Check the index patterns and make sure the key has both
readandview_index_metadatafor the required indices. - Connector or model requests fail
- Add
feature_actions.readfor Kibana connectors. Addmonitor_inferencefor Elasticsearch inference endpoints and tools that use the Elasticsearch Inference API. - Workflow requests fail
- Add
feature_workflowsManagement.readto read workflows,feature_workflowsManagement.workflow_executeto run them, orfeature_workflowsManagement.allto manage them. - The create API rejects the role descriptor for a derived key
- Authenticate the create request as a user. When the request is authenticated with an API key, Elasticsearch requires an explicit role descriptor with no privileges.