Overview
A client-mode connector for the Elasticsearch REST API that writes MQTT data into Elasticsearch and reads it back:
Topics use
data/elasticsearch/<object>/<verb>, and replies go to <topic>/response. BASE_ADDRESS has no trailing slash; one connector instance talks to one cluster or project:
Copy the Elasticsearch endpoint from the Elastic Cloud console (Manage / Connection details), not the Kibana URL.
Auth
Every event sendsAuthorization: ApiKey …. The template reads the key from the MQTT payload field api_key. Keep it in a Hub secret such as GET SECRET "ELASTICSEARCH_API_KEY" and never commit it.
- API key (recommended, required on Serverless): create one in Kibana (Stack Management → API keys) or with
POST /_security/api_key, and use theencodedvalue, which is base64 ofid:api_key. See Elasticsearch API keys. - Scope the key to what the connector writes. A key like the one used in testing:
manage_index_templates once the template exists, and drop index if the connector only appends (create_doc).
- Basic auth (alternative, self-managed and Hosted): remove the
Authorizationheader lines and addWITH USERNAME "coreflux_writer"andWITH PASSWORD GET SECRET "ELASTICSEARCH_PASSWORD"toREST_API_CONFIG. Don’t use theelasticsuperuser.
401 security_exception means the key is missing, wrong or expired. A 403 naming an action such as indices:admin/auto_create means the key is valid but lacks that privilege on that index.
Basic Syntax
JSON bodies come from the payload field
body, so control fields (api_key, index, id, name) are not sent to Elasticsearch. BulkIndex sends the payload field content as the raw NDJSON body.Example MQTT payloads
Index one reading into a data stream (data/elasticsearch/document/index):
data/elasticsearch/bulk). Every line ends in \n, including the last one. Data streams only accept create:
data/elasticsearch/document/put, then data/elasticsearch/document/update):
data/elasticsearch/search):
data/elasticsearch/esql/query):
data/elasticsearch/index-template/put):
data/elasticsearch/cluster/info): { "api_key": "<…>" }.
Gotchas
_bulkreturns200even when items fail. Check"errors": trueand eachitems[].<action>.statusin the response. A body that doesn’t end in a newline is rejected with400The bulk request must be terminated by a newline [\n].- Data streams are append-only. Each document needs
@timestamp. In_bulk, usecreate, notindex.PUT /{ds}/_doc/{id}and_updateare rejected on data streams; use a regular index (such asfactory-assets) for latest-state documents. - Index names must be lowercase and can’t start with
_,-or+. Several indices can be comma-separated inSearch,CountDocumentsandRefreshIndex(for examplefactory-telemetry,metrics-coreflux-*). - Near real-time: new documents become searchable after the next refresh (about 1 s by default; on Serverless refreshes are managed). Call
RefreshIndexonly in tests or after a batch, never per document. - Self-managed TLS: Elasticsearch 8.x and 9.x turn on TLS with a self-signed CA at first start. The broker host must trust that CA (or use a publicly trusted certificate) for
USE_SSL "true"to work. - Serverless doesn’t expose every API. Per Elastic’s Serverless OpenAPI,
GET /_cluster/healthis not available there (useGET /as the smoke instead), and some index settings such asnumber_of_replicasare managed for you. Indexing,_bulk, search, count,_update,_refresh, ES|QL, index templates and data streams are all available. - Deletes (documents, indices, data streams, templates),
_delete_by_query,_update_by_query, security and API key management, cluster settings, snapshots, ILM and Kibana APIs are left out on purpose.
Rate limits
Elasticsearch has no fixed request quota. When the write thread pool queue is full, it returns429 es_rejected_execution_exception, either for the whole request or for individual _bulk items. Back off and retry only the rejected items. Elastic Cloud Serverless also applies per-project ingest limits. See Tune for indexing speed.
Testing
Status: ready (beta). On 2026-10-04 every event was sent over HTTP, built exactly as the connector builds it (method, endpoint, headers and body substituted from sample MQTT payloads), against a local Elasticsearch 9.5.4 with security on and a scoped API key:
Not tested yet: Elastic Cloud Hosted or Serverless, TLS to a self-managed node, and a broker MQTT round-trip (including how the broker substitutes newlines in
content for _bulk).

