Onboard search data
This tutorial creates a synthetic docs-search-default data stream. Use a
separate naming, mapping, lifecycle, and relevance design for production data.
Before you begin
You need:
- the deployment-derived Elasticsearch URL;
- working DNS and TLS;
- an administrator with permission to create index templates and API keys;
- approval to create and delete tutorial resources.
Set the endpoint without embedding credentials:
export ELASTICSEARCH_URL="https://<deployment-elasticsearch-hostname>"
Create the data-stream template
curl --fail-with-body --user "<search-administrator>" \
--request PUT "${ELASTICSEARCH_URL}/_index_template/docs-search-template" \
--header "Content-Type: application/json" \
--data '{
"index_patterns": ["docs-search-*"],
"data_stream": {},
"template": {
"mappings": {
"properties": {
"@timestamp": {"type": "date"},
"title": {"type": "text"},
"body": {"type": "text"},
"source_id": {"type": "keyword"}
}
}
}
}'
Confirm the response contains "acknowledged":true.
Create the writer API key
curl --fail-with-body --user "<api-key-administrator>" \
--request POST "${ELASTICSEARCH_URL}/_security/api_key" \
--header "Content-Type: application/json" \
--data '{
"name": "docs-search-writer",
"expiration": "7d",
"role_descriptors": {
"docs_search_writer": {
"indices": [
{
"names": ["docs-search-*"],
"privileges": ["auto_configure", "create_doc"]
}
]
}
}
}'
Confirm that the response contains an API-key ID and encoded key. Store both in the approved secret store.
Create the validation API key
Use a separate read-only identity for the tutorial search:
curl --fail-with-body --user "<api-key-administrator>" \
--request POST "${ELASTICSEARCH_URL}/_security/api_key" \
--header "Content-Type: application/json" \
--data '{
"name": "docs-search-validator",
"expiration": "7d",
"role_descriptors": {
"docs_search_validator": {
"indices": [
{
"names": ["docs-search-*"],
"privileges": ["read"]
}
]
}
}
}'
Store the validation key and its ID separately from the writer key. A
production ingestion identity normally does not need read.
Load the keys without echoing them
Retrieve the encoded values from the approved secret store and enter them at the prompts:
IFS= read -rsp "Writer API key: " ELASTIC_WRITE_API_KEY
printf "\n"
IFS= read -rsp "Validation API key: " ELASTIC_READ_API_KEY
printf "\n"
The secret input is not echoed and is not part of the command stored in Bash history. Do not export either variable, save it in a shell profile, or enter the value directly on a command line.
Index and search a document
curl --fail-with-body \
--request POST \
"${ELASTICSEARCH_URL}/docs-search-default/_doc?op_type=create&refresh=wait_for" \
--header "Authorization: ApiKey ${ELASTIC_WRITE_API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"@timestamp": "2026-07-29T00:00:00Z",
"title": "Synthetic onboarding document",
"body": "This document validates the managed search ingestion path.",
"source_id": "docs-tutorial-001"
}'
Confirm the response reports "result":"created", then search:
curl --fail-with-body \
"${ELASTICSEARCH_URL}/docs-search-default/_search?q=source_id:docs-tutorial-001" \
--header "Authorization: ApiKey ${ELASTIC_READ_API_KEY}"
The response must contain exactly the synthetic document. Remove the keys from the current shell immediately after validation:
unset ELASTIC_WRITE_API_KEY ELASTIC_READ_API_KEY
Clean up
Delete the tutorial data stream and template with an approved administrator, then invalidate the API key:
curl --fail-with-body --user "<search-administrator>" \
--request DELETE "${ELASTICSEARCH_URL}/_data_stream/docs-search-default"
curl --fail-with-body --user "<search-administrator>" \
--request DELETE "${ELASTICSEARCH_URL}/_index_template/docs-search-template"
Use both API-key IDs returned at creation time with the invalidate API. Do not reuse either tutorial key for production.