diff --git a/.ci/Dockerfile b/.ci/Dockerfile
new file mode 100644
index 0000000000..e3a5f95e45
--- /dev/null
+++ b/.ci/Dockerfile
@@ -0,0 +1,27 @@
+# $ docker build --file Dockerfile --tag elastic/go-elasticsearch .
+#
+# $ docker run -it --env ELASTICSEARCH_URL=http://es1:9200 --network elasticsearch --rm elastic/go-elasticsearch go run _examples/main.go
+#
+
+ARG  VERSION=1-alpine
+FROM golang:${VERSION}
+
+RUN apk add --no-cache --quiet make curl git jq unzip tree && \
+    go get -u golang.org/x/lint/golint && \
+    curl -sSL --retry 3 --retry-connrefused https://github.com/gotestyourself/gotestsum/releases/download/v1.6.1/gotestsum_1.6.1_linux_amd64.tar.gz | tar -xz -C /usr/local/bin gotestsum
+
+VOLUME ["/tmp"]
+
+ENV CGO_ENABLED=0
+ENV TERM xterm-256color
+
+WORKDIR /go-elasticsearch
+
+COPY . .
+
+RUN go mod download
+
+WORKDIR internal/cmd/generate
+RUN go mod download
+
+WORKDIR /go-elasticsearch
\ No newline at end of file
diff --git a/.ci/certs/ca.crt b/.ci/certs/ca.crt
new file mode 100644
index 0000000000..42db5a2274
--- /dev/null
+++ b/.ci/certs/ca.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUGqPn96yNRroRX2uBi+m999M4GwIwDQYJKoZIhvcNAQEL
+BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
+cmF0ZWQgQ0EwHhcNMjAwNDI5MDUyMzI2WhcNMjEwNDI5MDUyMzI2WjA0MTIwMAYD
+VQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIsS6eBX4PK3xiU5+mWG2pj6
+T/3GzOkYRmHPqOsIdVylKeqg5p42y8u3UrSk4pqWg7oifwZTJkOQOuoZMoqAE9C1
+lwHJfdvyltjg/BAj4+3s3QqxWWMy1ATNXvYYOxhgC5F7URLYKdEKxYjWkZIxChcy
+2oEpYSezDb1KnnraDz+snawTUVAqiHgsjmEMqueJZGj78dULf6kgsDRbGVecVy+B
+D9aFUgnB0Tb8i2BbU90LwknKqJGmQ0JwMRBWoGXJ/jhOr1bYhx8RUWZVglF/Q6MZ
+Es63oW45POm+OLlZk8Lnvzth7DS37v8wPID8cc00Dsb1g2s7ValacesdFn8huyUC
+AwEAAaNTMFEwHQYDVR0OBBYEFAoBzyNNN2Uz/J/pQP6o8Mj2OvEWMB8GA1UdIwQY
+MBaAFAoBzyNNN2Uz/J/pQP6o8Mj2OvEWMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBACV43c28cDSpX1FICI37pITRRzw4O9PG/HKrf307/jIieHTb
+HPR6W27YZcwaI5Mtut6DkloM6I44uC87zqzCpxnSdmhEzMIcKjQbIBZEItvrJURd
+2ll4RcXrAEznbwng9Z90W3WOgWjX91AA6Y/TCYgCxa9/qA99RLvJlU4VkQ6QUE4X
+e2nSdBBBTUgARVM+0nDxPvE00GR598UA/UFiXtKJNZv3BNt5viPefFYXItuzlmsQ
+7ZkLqGOYcHrH/rdSzS4R2D1WjlzPBx4z5D7+3XQV2mjRJmahKZj8F0icnZPq9Uk2
+nehNyMis+kGplpUspadB+HUKt6uaCwR+ELOPyhU=
+-----END CERTIFICATE-----
diff --git a/.ci/certs/testnode.crt b/.ci/certs/testnode.crt
new file mode 100644
index 0000000000..af58a18d1d
--- /dev/null
+++ b/.ci/certs/testnode.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDYjCCAkqgAwIBAgIVAIZQH0fe5U+bGQ6m1JUBO/AQkQ/9MA0GCSqGSIb3DQEB
+CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu
+ZXJhdGVkIENBMB4XDTIwMDMyNzE5MTcxMVoXDTIzMDMyNzE5MTcxMVowEzERMA8G
+A1UEAxMIaW5zdGFuY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB
+fco1t1+sE1gTwTVGcXKZqJTP2GjMHM0cfJE5KKfwC5B+pHADRT6FZxvepgKjEBDt
+CK+2Rmotyeb15XXMSKguNhyT+2PuKvT5r05L7P91XRYXrwxG2swJPtct7A87xdFa
+Ek+YRpqGGmTaux2jOELMiAmqEzoj6w/xFq+LF4SolTW4wOL2eLFkEFHBX2oCwU5T
+Q+B+7E9zL45nFWlkeRGJ+ZQTnRNZ/1r4N9A9Gtj4x/H1/y4inWndikdxAb5QiEYJ
+T+vbQWzHYWjz13ttHJsz+6T8rvA1jK+buHgVh4K8lV13X9k54soBqHB8va7/KIJP
+g8gvd6vusEI7Bmfl1as7AgMBAAGjgYswgYgwHQYDVR0OBBYEFKnnpvuVYwtFSUis
+WwN9OHLyExzJMB8GA1UdIwQYMBaAFJYCWKn16g+acbing4Vl45QGUBs0MDsGA1Ud
+EQQ0MDKCCWxvY2FsaG9zdIIIaW5zdGFuY2WHBH8AAAGHEAAAAAAAAAAAAAAAAAAA
+AAGCA2VzMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAPNsIoD4GBrTgR
+jfvBuHS6eU16P95m16O8Mdpr4SMQgWLQUhs8aoVgfwpg2TkbCWxOe6khJOyNm7bf
+fW4aFQ/OHcQV4Czz3c7eOHTWSyMlCOv+nRXd4giJZ5TOHw1zKGmKXOIvhvE6RfdF
+uBBfrusk164H4iykm0Bbr/wo4d6wuebp3ZYLPw5zV0D08rsaR+3VJ9VxWuFpdm/r
+2onYOohyuX9DRjAczasC+CRRQN4eHJlRfSQB8WfTKw3EloRJJDAg6SJyGiAJ++BF
+hnqfNcEyKes2AWagFF9aTbEJMrzMhH+YB5F+S/PWvMUlFzcoocVKqc4pIrjKUNWO
+6nbTxeAB
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/.ci/certs/testnode.key b/.ci/certs/testnode.key
new file mode 100644
index 0000000000..2d56799798
--- /dev/null
+++ b/.ci/certs/testnode.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwX3KNbdfrBNYE8E1RnFymaiUz9hozBzNHHyROSin8AuQfqRw
+A0U+hWcb3qYCoxAQ7QivtkZqLcnm9eV1zEioLjYck/tj7ir0+a9OS+z/dV0WF68M
+RtrMCT7XLewPO8XRWhJPmEaahhpk2rsdozhCzIgJqhM6I+sP8RavixeEqJU1uMDi
+9nixZBBRwV9qAsFOU0PgfuxPcy+OZxVpZHkRifmUE50TWf9a+DfQPRrY+Mfx9f8u
+Ip1p3YpHcQG+UIhGCU/r20Fsx2Fo89d7bRybM/uk/K7wNYyvm7h4FYeCvJVdd1/Z
+OeLKAahwfL2u/yiCT4PIL3er7rBCOwZn5dWrOwIDAQABAoIBAFcm4ICnculf4Sks
+umFbUiISA81GjZV6V4zAMu1K+bGuk8vnJyjh9JJD6hK0NbXa07TgV7zDJKoxKd2S
+GCgGhfIin2asMcuh/6vDIYIjYsErR3stdlsnzAVSD7v4ergSlwR6AO32xz0mAE1h
+QK029yeHEstPU72/7/NIo5MD6dXAbut1MzgijZD8RQo1z21D6qmLcPTVTfkn7a3W
+MY3y7XUIkA1TOyIRsH3k6F6NBWkvtXbwOUeLCJ14EvS8T9BqhIhPDZv8mQTRLDOD
+tQRyC4Cnw+UhYmnMFJhj6N2jpTBv/AdoKcRC56uBJyPW+dxj6i4e7n3pQuxqRvpI
+LLJJsskCgYEA4QQxzuJizLKV75rE+Qxg0Ej0Gid1aj3H5eeTZOUhm9KC8KDfPdpk
+msKaNzJq/VDcqHPluGS1jYZVgZlal1nk5xKBcbQ4n297VPVd+sLtlf0bj4atlDUO
++iOVo0H7k5yWvj+TzVRlc5zjDLcnQh8i+22o3+65hIrb2zpzg/cCZJ8CgYEA3CJX
+bjmWPQ0uZVIa8Wz8cJFtKT9uVl7Z3/f6HjN9I0b/9MmVlNxQVAilVwhDkzR/UawG
+QeRFBJ6XWRwX0aoMq+O9VSNu/R2rtEMpIYt3LwbI3yw6GRoCdB5qeL820O+KX5Fl
+/z+ZNgrHgA1yKPVf+8ke2ZtLEqPHMN+BMuq8t+UCgYEAy0MfvzQPbbuw55WWcyb0
+WZJdNzcHwKX4ajzrj4vP9VOPRtD7eINMt+QsrMnVjei6u0yeahhHTIXZvc2K4Qeq
+V/YGinDzaUqqTU+synXFauUOPXO6XxQi6GC2rphPKsOcBFWoLSYc0vgYvgbA5uD7
+l8Yyc77RROKuwfWmHcJHHh8CgYBurGFSjGdJWHgr/oSHPqkIG0VLiJV7nQJjBPRd
+/Lr8YnTK6BJpHf7Q0Ov3frMirjEYqakXtaExel5TMbmT8q+eN8h3pnHlleY+oclr
+EQghv4J8GWs4NYhoQuZ6wH/ZuaTS+XHTS3FG51J3wcrUZtET8ICvHNE4lNjPbH8z
+TysENQKBgHER1RtDFdz+O7mlWibrHk8JDgcVdZV/pBF+9cb7r/orkH9RLAHDlsAO
+tuSVaQmm5eqgaAxMamBXSyw1lir07byemyuEDg0mJ1rNUGsAY8P+LWr579gvKMme
+5gvrJr99JkBTV3z+TiL7dZa52eW00Ijqg2qcbHGpq3kXWWkbd8Tn
+-----END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/.ci/functions/cleanup.sh b/.ci/functions/cleanup.sh
new file mode 100644
index 0000000000..865b40da87
--- /dev/null
+++ b/.ci/functions/cleanup.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+#
+# Shared cleanup routines between different steps
+#
+# Please source .ci/functions/imports.sh as a whole not just this file
+#
+# Version 1.0.0
+# - Initial version after refactor
+
+function cleanup_volume {
+  if [[ "$(docker volume ls -q -f name=$1)" ]]; then
+    echo -e "\033[34;1mINFO:\033[0m Removing volume $1\033[0m"
+    (docker volume rm "$1") || true
+  fi
+}
+function container_running {
+  if [[ "$(docker ps -q -f name=$1)" ]]; then
+    return 0;
+    else return 1;
+  fi
+}
+function cleanup_node {
+  if container_running "$1"; then
+    echo -e "\033[34;1mINFO:\033[0m Removing container $1\033[0m"
+    (docker container rm --force --volumes "$1") || true
+  fi
+  if [[ -n "$1" ]]; then
+    echo -e "\033[34;1mINFO:\033[0m Removing volume $1-${suffix}-data\033[0m"
+    cleanup_volume "$1-${suffix}-data"
+  fi
+}
+function cleanup_network {
+  if [[ "$(docker network ls -q -f name=$1)" ]]; then
+    echo -e "\033[34;1mINFO:\033[0m Removing network $1\033[0m"
+    (docker network rm "$1") || true
+  fi
+}
+
+function cleanup_trap {
+  status=$?
+  set +x
+  if [[ "$DETACH" != "true" ]]; then
+    echo -e "\033[34;1mINFO:\033[0m clean the network if not detached (start and exit)\033[0m"
+    cleanup_all_in_network "$1"
+  fi
+  # status is 0 or SIGINT
+  if [[ "$status" == "0" || "$status" == "130" ]]; then
+    echo -e "\n\033[32;1mSUCCESS run-tests\033[0m"
+    exit 0
+  else
+    echo -e "\n\033[31;1mFAILURE during run-tests\033[0m"
+    exit ${status}
+  fi
+};
+function cleanup_all_in_network {
+
+  if [[ -z "$(docker network ls -q -f name="^$1\$")" ]]; then
+    echo -e "\033[34;1mINFO:\033[0m $1 is already deleted\033[0m"
+    return 0
+  fi
+  containers=$(docker network inspect -f '{{ range $key, $value := .Containers }}{{ printf "%s\n" .Name}}{{ end }}' $1)
+  while read -r container; do
+    cleanup_node "$container"
+  done <<< "$containers"
+  cleanup_network $1
+  echo -e "\033[32;1mSUCCESS:\033[0m Cleaned up and exiting\033[0m"
+};
\ No newline at end of file
diff --git a/.ci/functions/imports.sh b/.ci/functions/imports.sh
new file mode 100644
index 0000000000..3fb28cc388
--- /dev/null
+++ b/.ci/functions/imports.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+#
+# Sets up all the common variables and imports relevant functions
+#
+# Version 1.0.1
+# - Initial version after refactor
+# - Validate STACK_VERSION asap
+
+function require_stack_version() {
+  if [[ -z $STACK_VERSION ]]; then
+    echo -e "\033[31;1mERROR:\033[0m Required environment variable [STACK_VERSION] not set\033[0m"
+    exit 1
+  fi
+}
+
+require_stack_version
+
+if [[ -z $es_node_name ]]; then
+  # only set these once
+  set -euo pipefail
+  export TEST_SUITE=${TEST_SUITE-free}
+  export RUNSCRIPTS=${RUNSCRIPTS-}
+  export DETACH=${DETACH-false}
+  export CLEANUP=${CLEANUP-false}
+
+  export es_node_name=instance
+  export elastic_password=changeme
+  export elasticsearch_image=elasticsearch
+  export elasticsearch_url=https://elastic:${elastic_password}@${es_node_name}:9200
+  if [[ $TEST_SUITE != "platinum" ]]; then
+    export elasticsearch_url=http://${es_node_name}:9200
+  fi
+  export external_elasticsearch_url=${elasticsearch_url/$es_node_name/localhost}
+  export elasticsearch_container="${elasticsearch_image}:${STACK_VERSION}"
+
+  export suffix=rest-test
+  export moniker=$(echo "$elasticsearch_container" | tr -C "[:alnum:]" '-')
+  export network_name=${moniker}${suffix}
+
+  export ssl_cert="${script_path}/certs/testnode.crt"
+  export ssl_key="${script_path}/certs/testnode.key"
+  export ssl_ca="${script_path}/certs/ca.crt"
+
+fi
+
+  export script_path=$(dirname $(realpath -s $0))
+  source $script_path/functions/cleanup.sh
+  source $script_path/functions/wait-for-container.sh
+  trap "cleanup_trap ${network_name}" EXIT
+
+
+if [[ "$CLEANUP" == "true" ]]; then
+  cleanup_all_in_network $network_name
+  exit 0
+fi
+
+echo -e "\033[34;1mINFO:\033[0m Creating network $network_name if it does not exist already \033[0m"
+docker network inspect "$network_name" > /dev/null 2>&1 || docker network create "$network_name"
+
diff --git a/.ci/functions/wait-for-container.sh b/.ci/functions/wait-for-container.sh
new file mode 100644
index 0000000000..17343aab0d
--- /dev/null
+++ b/.ci/functions/wait-for-container.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# Exposes a routine scripts can call to wait for a container if that container set up a health command
+#
+# Please source .ci/functions/imports.sh as a whole not just this file
+#
+# Version 1.0.1
+# - Initial version after refactor
+# - Make sure wait_for_contiainer is silent
+
+function wait_for_container {
+  set +x
+  until ! container_running "$1" || (container_running "$1" && [[ "$(docker inspect -f "{{.State.Health.Status}}" ${1})" != "starting" ]]); do
+    echo ""
+    docker inspect -f "{{range .State.Health.Log}}{{.Output}}{{end}}" ${1}
+    echo -e "\033[34;1mINFO:\033[0m waiting for node $1 to be up\033[0m"
+    sleep 2;
+  done;
+
+  # Always show logs if the container is running, this is very useful both on CI as well as while developing
+  if container_running $1; then
+    docker logs $1
+  fi
+
+  if ! container_running $1 || [[ "$(docker inspect -f "{{.State.Health.Status}}" ${1})" != "healthy" ]]; then
+    cleanup_all_in_network $2
+    echo
+    echo -e "\033[31;1mERROR:\033[0m Failed to start $1 in detached mode beyond health checks\033[0m"
+    echo -e "\033[31;1mERROR:\033[0m dumped the docker log before shutting the node down\033[0m"
+    return 1
+  else
+    echo
+    echo -e "\033[32;1mSUCCESS:\033[0m Detached and healthy: ${1} on docker network: ${network_name}\033[0m"
+    return 0
+  fi
+}
\ No newline at end of file
diff --git a/.jenkins/jobs/defaults.yml b/.ci/jobs/defaults.yml
old mode 100755
new mode 100644
similarity index 83%
rename from .jenkins/jobs/defaults.yml
rename to .ci/jobs/defaults.yml
index 1f38d82487..7b8a45c254
--- a/.jenkins/jobs/defaults.yml
+++ b/.ci/jobs/defaults.yml
@@ -45,15 +45,19 @@
         - linux
     - axis:
         type: yaml
-        filename: .jenkins/test-matrix.yml
-        name: ELASTICSEARCH_VERSION
+        filename: .ci/test-matrix.yml
+        name: STACK_VERSION
     - axis:
         type: yaml
-        filename: .jenkins/test-matrix.yml
+        filename: .ci/test-matrix.yml
         name: GO_VERSION
+    - axis:
+        type: yaml
+        filename: .ci/test-matrix.yml
+        name: TEST_SUITE
     yaml-strategy:
       exclude-key: exclude
-      filename: .jenkins/test-matrix.yml
+      filename: .ci/test-matrix.yml
     wrappers:
       - ansicolor
       - timeout:
@@ -65,10 +69,10 @@
     builders:
       - shell: |-
           #!/usr/local/bin/runbld
-          .jenkins/run-tests
+          .ci/run-tests
     publishers:
       - email:
-          recipients: infra-root+build@elastic.co
+          recipients: build-lang-clients@elastic.co
       - junit:
           results: "*-junit.xml"
           allow-empty-results: true
diff --git a/.jenkins/jobs/elastic+go-elasticsearch+6.x.yml b/.ci/jobs/elastic+go-elasticsearch+6.x.yml
old mode 100755
new mode 100644
similarity index 100%
rename from .jenkins/jobs/elastic+go-elasticsearch+6.x.yml
rename to .ci/jobs/elastic+go-elasticsearch+6.x.yml
diff --git a/.ci/jobs/elastic+go-elasticsearch+7.12.yml b/.ci/jobs/elastic+go-elasticsearch+7.12.yml
new file mode 100644
index 0000000000..b29036f1b9
--- /dev/null
+++ b/.ci/jobs/elastic+go-elasticsearch+7.12.yml
@@ -0,0 +1,15 @@
+---
+- job:
+    name: elastic+go-elasticsearch+7.12
+    display-name: 'elastic / go-elasticsearch # 7.12'
+    description: Testing the go-elasticsearch 7.12 branch.
+    junit_results: "*-junit.xml"
+    parameters:
+      - string:
+          name: branch_specifier
+          default: refs/heads/7.12
+          description: The Git branch specifier to build
+    triggers:
+      - github
+      - timed: 'H */12 * * *'
+
diff --git a/.jenkins/jobs/elastic+go-elasticsearch+5.x.yml b/.ci/jobs/elastic+go-elasticsearch+7.16.yml
old mode 100755
new mode 100644
similarity index 53%
rename from .jenkins/jobs/elastic+go-elasticsearch+5.x.yml
rename to .ci/jobs/elastic+go-elasticsearch+7.16.yml
index bff81cf84b..1519463f50
--- a/.jenkins/jobs/elastic+go-elasticsearch+5.x.yml
+++ b/.ci/jobs/elastic+go-elasticsearch+7.16.yml
@@ -1,13 +1,13 @@
 ---
 - job:
-    name: elastic+go-elasticsearch+5.x
-    display-name: 'elastic / go-elasticsearch # 5.x'
-    description: Testing the go-elasticsearch 5.x branch.
+    name: elastic+go-elasticsearch+7.16
+    display-name: 'elastic / go-elasticsearch # 7.16'
+    description: Testing the go-elasticsearch 7.16 branch.
     junit_results: "*-junit.xml"
     parameters:
       - string:
           name: branch_specifier
-          default: refs/heads/5.x
+          default: refs/heads/7.16
           description: The Git branch specifier to build
     triggers:
       - github
diff --git a/.jenkins/jobs/elastic+go-elasticsearch+master.yml b/.ci/jobs/elastic+go-elasticsearch+master.yml
old mode 100755
new mode 100644
similarity index 100%
rename from .jenkins/jobs/elastic+go-elasticsearch+master.yml
rename to .ci/jobs/elastic+go-elasticsearch+master.yml
diff --git a/.ci/run-elasticsearch.sh b/.ci/run-elasticsearch.sh
new file mode 100755
index 0000000000..1ae249e984
--- /dev/null
+++ b/.ci/run-elasticsearch.sh
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+#
+# Launch one or more Elasticsearch nodes via the Docker image,
+# to form a cluster suitable for running the REST API tests.
+#
+# Export the STACK_VERSION variable, eg. '8.0.0-SNAPSHOT'.
+# Export the TEST_SUITE variable, eg. 'free' or 'platinum' defaults to 'free'.
+# Export the NUMBER_OF_NODES variable to start more than 1 node
+
+# Version 1.3.0
+# - Initial version of the run-elasticsearch.sh script
+# - Deleting the volume should not dependent on the container still running
+# - Fixed `ES_JAVA_OPTS` config
+# - Moved to STACK_VERSION and TEST_VERSION
+# - Refactored into functions and imports
+# - Support NUMBER_OF_NODES
+# - Added 5 retries on docker pull for fixing transient network errors
+# - Added flags to make local CCR configurations work
+# - Added action.destructive_requires_name=false as the default will be true in v8
+
+script_path=$(dirname $(realpath -s $0))
+source $script_path/functions/imports.sh
+set -euo pipefail
+
+echo -e "\033[34;1mINFO:\033[0m Take down node if called twice with the same arguments (DETACH=true) or on seperate terminals \033[0m"
+cleanup_node $es_node_name
+
+master_node_name=${es_node_name}
+cluster_name=${moniker}${suffix}
+
+declare -a volumes
+environment=($(cat <<-END
+  --env node.name=$es_node_name
+  --env cluster.name=$cluster_name
+  --env cluster.initial_master_nodes=$master_node_name
+  --env discovery.seed_hosts=$master_node_name
+  --env cluster.routing.allocation.disk.threshold_enabled=false
+  --env bootstrap.memory_lock=true
+  --env node.attr.testattr=test
+  --env path.repo=/tmp
+  --env repositories.url.allowed_urls=http://snapshot.test*
+  --env action.destructive_requires_name=false
+  --env ingest.geoip.downloader.enabled=false
+END
+))
+if [[ "$TEST_SUITE" == "platinum" ]]; then
+  environment+=($(cat <<-END
+    --env ELASTIC_PASSWORD=$elastic_password
+    --env xpack.license.self_generated.type=trial
+    --env xpack.security.enabled=true
+    --env xpack.security.http.ssl.enabled=true
+    --env xpack.security.http.ssl.key=certs/testnode.key
+    --env xpack.security.http.ssl.certificate=certs/testnode.crt
+    --env xpack.security.http.ssl.certificate_authorities=certs/ca.crt
+    --env xpack.security.transport.ssl.enabled=true
+    --env xpack.security.transport.ssl.verification_mode=certificate
+    --env xpack.security.transport.ssl.key=certs/testnode.key
+    --env xpack.security.transport.ssl.certificate=certs/testnode.crt
+    --env xpack.security.transport.ssl.certificate_authorities=certs/ca.crt
+END
+))
+  volumes+=($(cat <<-END
+    --volume $ssl_cert:/usr/share/elasticsearch/config/certs/testnode.crt
+    --volume $ssl_key:/usr/share/elasticsearch/config/certs/testnode.key
+    --volume $ssl_ca:/usr/share/elasticsearch/config/certs/ca.crt
+END
+))
+fi
+
+cert_validation_flags=""
+if [[ "$TEST_SUITE" == "platinum" ]]; then
+  cert_validation_flags="--insecure --cacert /usr/share/elasticsearch/config/certs/ca.crt --resolve ${es_node_name}:443:127.0.0.1"
+fi
+
+# Pull the container, retry on failures up to 5 times with
+# short delays between each attempt. Fixes most transient network errors.
+docker_pull_attempts=0
+until [ "$docker_pull_attempts" -ge 5 ]
+do
+   docker pull docker.elastic.co/elasticsearch/"$elasticsearch_container" && break
+   docker_pull_attempts=$((docker_pull_attempts+1))
+   echo "Failed to pull image, retrying in 10 seconds (retry $docker_pull_attempts/5)..."
+   sleep 10
+done
+
+NUMBER_OF_NODES=${NUMBER_OF_NODES-1}
+http_port=9200
+for (( i=0; i<$NUMBER_OF_NODES; i++, http_port++ )); do
+  node_name=${es_node_name}$i
+  node_url=${external_elasticsearch_url/9200/${http_port}}$i
+  if [[ "$i" == "0" ]]; then node_name=$es_node_name; fi
+  environment+=($(cat <<-END
+    --env node.name=$node_name
+END
+))
+  echo "$i: $http_port $node_url "
+  volume_name=${node_name}-${suffix}-data
+  volumes+=($(cat <<-END
+    --volume $volume_name:/usr/share/elasticsearch/data${i}
+END
+))
+
+  # make sure we detach for all but the last node if DETACH=false (default) so all nodes are started
+  local_detach="true"
+  if [[ "$i" == "$((NUMBER_OF_NODES-1))" ]]; then local_detach=$DETACH; fi
+  echo -e "\033[34;1mINFO:\033[0m Starting container $node_name \033[0m"
+  set -x
+  docker run \
+    --name "$node_name" \
+    --network "$network_name" \
+    --env "ES_JAVA_OPTS=-Xms1g -Xmx1g -da:org.elasticsearch.xpack.ccr.index.engine.FollowingEngineAssertions" \
+    "${environment[@]}" \
+    "${volumes[@]}" \
+    --publish "$http_port":9200 \
+    --ulimit nofile=65536:65536 \
+    --ulimit memlock=-1:-1 \
+    --detach="$local_detach" \
+    --health-cmd="curl $cert_validation_flags --fail $elasticsearch_url/_cluster/health || exit 1" \
+    --health-interval=2s \
+    --health-retries=20 \
+    --health-timeout=2s \
+    --rm \
+    docker.elastic.co/elasticsearch/"$elasticsearch_container";
+
+  set +x
+  if wait_for_container "$es_node_name" "$network_name"; then
+    echo -e "\033[32;1mSUCCESS:\033[0m Running on: $node_url\033[0m"
+  fi
+
+done
diff --git a/.ci/run-repository.sh b/.ci/run-repository.sh
new file mode 100644
index 0000000000..fa1b716111
--- /dev/null
+++ b/.ci/run-repository.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+#
+# Called by entry point `run-test` use this script to add your repository specific test commands
+#
+# Once called Elasticsearch is up and running
+#
+# Its recommended to call `imports.sh` as defined here so that you get access to all variables defined there
+#
+# Any parameters that test-matrix.yml defines should be declared here with appropiate defaults
+
+script_path=$(dirname $(realpath -s $0))
+source $script_path/functions/imports.sh
+set -euo pipefail
+
+echo -e "\033[34;1mINFO:\033[0m VERSION: ${STACK_VERSION}\033[0m"
+echo -e "\033[34;1mINFO:\033[0m TEST_SUITE: ${TEST_SUITE}\033[0m"
+echo -e "\033[34;1mINFO:\033[0m RUNSCRIPTS: ${RUNSCRIPTS}\033[0m"
+echo -e "\033[34;1mINFO:\033[0m URL: ${elasticsearch_url}\033[0m"
+
+echo -e "\033[34;1mINFO:\033[0m pinging Elasticsearch ..\033[0m"
+curl --insecure --fail $external_elasticsearch_url/_cluster/health?pretty
+
+if [[ "$RUNSCRIPTS" = *"enterprise-search"* ]]; then
+  enterprise_search_url="http://localhost:3002"
+  echo -e "\033[34;1mINFO:\033[0m pinging Enterprise Search ..\033[0m"
+  curl -I --fail $enterprise_search_url
+fi
+
+echo -e "\033[32;1mSUCCESS:\033[0m successfully started the ${STACK_VERSION} stack.\033[0m"
+
+echo -e "\033[34;1mINFO:\033[0m Building the [elastic/go-elasticsearch] image... \033[0m"
+
+docker build \
+    --file .ci/Dockerfile \
+    --tag elastic/go-elasticsearch \
+    .
+
+echo -e "\033[34;1mINFO:\033[0m Retrieving Elasticsearch Version & Hash from container... \033[0m"
+
+ELASTICSEARCH_BUILD_VERSION=$(curl -sSk $external_elasticsearch_url | jq -r '.version.number')
+ELASTICSEARCH_BUILD_HASH=$(curl -sSk $external_elasticsearch_url | jq -r '.version.build_hash')
+
+echo -e "\033[34;1mINFO:\033[0m Download Elasticsearch specs... \033[0m"
+docker run --volume=$WORKSPACE/tmp:/tmp --workdir=/go-elasticsearch/internal/build --rm elastic/go-elasticsearch /bin/sh -c "
+  go mod download
+  go run main.go download-spec -o /tmp -d
+"
+
+echo -e "\033[34;1mINFO:\033[0m Execute [$TEST_SUITE] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+docker run -t \
+  --volume=$WORKSPACE/tmp:/tmp \
+  --rm \
+  --network "$network_name" \
+  --env "ELASTICSEARCH_URL=$elasticsearch_url" \
+  --env "ELASTICSEARCH_VERSION=$STACK_VERSION" \
+  --env "ELASTICSEARCH_BUILD_VERSION=$ELASTICSEARCH_BUILD_VERSION" \
+  --env "ELASTICSEARCH_BUILD_HASH=$ELASTICSEARCH_BUILD_HASH" \
+  --env "WORKSPACE=${WORKSPACE:-/workspace}" \
+  --volume "${WORKSPACE:-workspace}:${WORKSPACE:-/workspace}" \
+  elastic/go-elasticsearch \
+  .ci/scripts/tests-$TEST_SUITE.sh
\ No newline at end of file
diff --git a/.ci/run-tests b/.ci/run-tests
new file mode 100755
index 0000000000..5166c457b7
--- /dev/null
+++ b/.ci/run-tests
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+#
+# Version 1.1
+# - Moved to .ci folder and seperated out `run-repository.sh`
+# - Add `$RUNSCRIPTS` env var for running Elasticsearch dependent products
+script_path=$(dirname $(realpath -s $0))
+source $script_path/functions/imports.sh
+set -euo pipefail
+
+echo -e "\033[1m>>>>> Start [$STACK_VERSION container] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+DETACH=true bash .ci/run-elasticsearch.sh
+
+if [[ -n "$RUNSCRIPTS" ]]; then
+  for RUNSCRIPT in ${RUNSCRIPTS//,/ } ; do
+    echo -e "\033[1m>>>>> Running run-$RUNSCRIPT.sh >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+    CONTAINER_NAME=${RUNSCRIPT} \
+      DETACH=true \
+      bash .ci/run-${RUNSCRIPT}.sh
+  done
+fi
+
+echo -e "\033[1m>>>>> Repository specific tests >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+bash .ci/run-repository.sh
\ No newline at end of file
diff --git a/.ci/scripts/benchmarks/run-benchmarks.sh b/.ci/scripts/benchmarks/run-benchmarks.sh
new file mode 100755
index 0000000000..9e1830ec07
--- /dev/null
+++ b/.ci/scripts/benchmarks/run-benchmarks.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+#
+# Licensed to Elasticsearch B.V. under one or more agreements.
+# Elasticsearch B.V. licenses this file to you under the Apache 2.0 License.
+# See the LICENSE file in the project root for more information.
+#
+# Runner for the client benchmarks.
+#
+# Export the following environment variables when running the script:
+#
+# * CLIENT_IMAGE
+# * CLIENT_BRANCH
+# * CLIENT_COMMAND
+#
+# The WORKSPACE environment variable is automatically set on Jenkins.
+#
+# The VAULT_ADDR is automatically set on Jenkins.
+
+set -euxo pipefail
+
+mkdir -p "$WORKSPACE/tmp"
+
+vault read -field=gcp_service_account secret/clients-team/benchmarking > "$WORKSPACE/tmp/credentials.json"
+
+export GOOGLE_CLOUD_KEYFILE_JSON="$WORKSPACE/tmp/credentials.json"
+export GOOGLE_APPLICATION_CREDENTIALS="$WORKSPACE/tmp/credentials.json"
+
+set +x
+report_url="$(vault read -field=reporting_url secret/clients-team/benchmarking)"
+report_password="$(vault read -field=reporting_password secret/clients-team/benchmarking)"
+export ELASTICSEARCH_REPORT_URL="$report_url"
+export ELASTICSEARCH_REPORT_PASSWORD="$report_password"
+
+export TF_VAR_reporting_url="$ELASTICSEARCH_REPORT_URL"
+export TF_VAR_reporting_password="$ELASTICSEARCH_REPORT_PASSWORD"
+
+runner_ssh_private_key="$(vault read -field=runner_ssh_private_key secret/clients-team/benchmarking)"
+runner_ssh_public_key="$(vault read -field=runner_ssh_public_key secret/clients-team/benchmarking)"
+export TF_VAR_runner_ssh_private_key="$runner_ssh_private_key"
+export TF_VAR_runner_ssh_public_key="$runner_ssh_public_key"
+echo "$runner_ssh_private_key" > "$WORKSPACE/tmp/runner_id_rsa"
+echo "$runner_ssh_public_key" > "$WORKSPACE/tmp/runner_id_rsa.pub"
+chmod go= "$WORKSPACE/tmp/runner_id_rsa"
+chmod go= "$WORKSPACE/tmp/runner_id_rsa.pub"
+set -x
+
+TERRAFORM=$(command -v terraform)
+GCLOUD=$(command -v gcloud)
+
+DESTROY=${DESTROY:-yes}
+
+function cleanup {
+  if [[ $DESTROY != "no" ]]; then
+    $TERRAFORM destroy --auto-approve --input=false --var client_image="$CLIENT_IMAGE"
+  fi
+}
+
+trap cleanup INT TERM EXIT;
+
+if [[ ! -d "$WORKSPACE/tmp/elasticsearch-clients-benchmarks" ]]; then
+  git clone --depth 1 git@github.com:elastic/elasticsearch-clients-benchmarks.git "$WORKSPACE/tmp/elasticsearch-clients-benchmarks"
+else
+  cd "$WORKSPACE/tmp/elasticsearch-clients-benchmarks" && git fetch --quiet && git reset origin/master --hard
+fi
+
+cd "$WORKSPACE/tmp/elasticsearch-clients-benchmarks/terraform/gcp"
+
+$TERRAFORM init --input=false
+$TERRAFORM apply --auto-approve --input=false --var client_image="$CLIENT_IMAGE"
+
+set +ex
+echo -e "\n\033[1mWaiting for instance [$($TERRAFORM output runner_instance_name)] to be ready...\033[0m"
+
+SECONDS=0
+while (( SECONDS < 900 )); do # Timeout: 15min
+  $GCLOUD compute --project 'elastic-clients' ssh runner@"$($TERRAFORM output runner_instance_name)" --zone='europe-west1-b' --ssh-key-file="$WORKSPACE/tmp/runner_id_rsa" --command="sudo su - runner -c 'docker container inspect -f \"{{.Name}}:{{.State.Status}}\" benchmarks-data'"
+  status=$?
+  if [[ $status -eq 0 ]]; then
+    break
+  else
+    sleep 1
+  fi
+done
+
+echo -e "\n\033[1mWaiting for cluster at [$($TERRAFORM output master_ip)] to be ready...\033[0m"
+
+SECONDS=0
+while (( SECONDS < 900 )); do # Timeout: 15min
+  $GCLOUD compute --project 'elastic-clients' ssh runner@"$($TERRAFORM output runner_instance_name)" --zone='europe-west1-b' --ssh-key-file="$WORKSPACE/tmp/runner_id_rsa" --command="sudo su - runner -c 'curl -sS $($TERRAFORM output master_ip):9200/_cat/nodes?v'"
+  status=$?
+  if [[ $status -eq 0 ]]; then
+    break
+  else
+    sleep 1
+  fi
+done
+
+echo -e "\n\033[1mRunning benchmarks for [$CLIENT_IMAGE]\033[0m"
+set -x
+
+$GCLOUD compute --project 'elastic-clients' ssh runner@"$($TERRAFORM output runner_instance_name)" \
+  --zone='europe-west1-b' \
+  --ssh-key-file="$WORKSPACE/tmp/runner_id_rsa" \
+  --ssh-flag='-t' \
+  --command="\
+  CLIENT_BRANCH=$CLIENT_BRANCH \
+  CLIENT_BENCHMARK_ENVIRONMENT=production \
+  /home/runner/runner.sh \"$CLIENT_COMMAND\""
diff --git a/.ci/scripts/tests-free.sh b/.ci/scripts/tests-free.sh
new file mode 100755
index 0000000000..d310d906cd
--- /dev/null
+++ b/.ci/scripts/tests-free.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env sh
+
+set -uo pipefail
+
+TIMEFORMAT="(Duration: %0lR)"
+
+echo -e "\033[34;1mINFO:\033[0m Cleaning up test files\033[0m"
+
+rm -rf esapi/test/*_test.go
+rm -rf esapi/test/xpack
+
+echo -e "\033[34;1mINFO:\033[0m Generating the API registry\033[0m"
+
+cd /go-elasticsearch/internal/build || exit
+go get -u golang.org/x/tools/cmd/goimports
+PACKAGE_PATH=/go-elasticsearch/esapi go generate ./...
+
+echo -e "\033[34;1mINFO:\033[0m Generating the test files\033[0m"
+
+go run main.go apitests --output '/go-elasticsearch/esapi/test' --input "/tmp/rest-api-spec/test/free/**/*.y*ml"
+
+echo -e "\033[34;1mINFO:\033[0m Download tests deps >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+cd /go-elasticsearch/esapi/test || exit
+go mod tidy
+
+echo -e "\033[34;1mINFO:\033[0m Running the tests\033[0m"
+
+gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-junit.xml -- -tags=integration -timeout=1h *_test.go
+status=$?
+
+exit $status
diff --git a/.ci/scripts/tests-platinum.sh b/.ci/scripts/tests-platinum.sh
new file mode 100755
index 0000000000..11eddbceb5
--- /dev/null
+++ b/.ci/scripts/tests-platinum.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env sh
+
+set -uo pipefail
+
+TIMEFORMAT="(Duration: %0lR)"
+
+echo -e "\033[34;1mINFO:\033[0m Cleaning up test files\033[0m"
+
+rm -rf esapi/test/*_test.go
+rm -rf rm -rf esapi/test/ml*
+
+echo -e "\033[34;1mINFO:\033[0m Generating the API registry\033[0m"
+
+cd /go-elasticsearch/internal/build || exit
+go get -u golang.org/x/tools/cmd/goimports
+PACKAGE_PATH=/go-elasticsearch/esapi go generate ./...
+
+echo -e "\033[34;1mINFO:\033[0m Generating the test files\033[0m"
+
+go run main.go apitests --output '/go-elasticsearch/esapi/test/xpack' --input '/tmp/rest-api-spec/test/platinum/**/*.yml'
+
+cd /go-elasticsearch || exit
+
+mkdir -p esapi/test/xpack/ml
+mkdir -p esapi/test/xpack/ml-crud
+
+mv esapi/test/xpack/xpack_ml* esapi/test/xpack/ml/
+mv esapi/test/xpack/ml/xpack_ml__jobs_crud_test.go esapi/test/xpack/ml-crud/
+
+set +e # Do not fail immediately when a single test suite fails
+
+echo -e "\033[34;1mINFO:\033[0m Download tests deps >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+cd /go-elasticsearch/esapi/test || exit
+go mod tidy
+
+echo -e "\033[34;1mINFO:\033[0m Running tests: XPACK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-junit.xml -- --tags=integration --timeout=1h -v xpack/*_test.go
+status1=$?
+
+echo -e "\033[34;1mINFO:\033[0m Running tests: XPACK ML >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-ml-junit.xml -- --tags=integration --timeout=1h -v ./xpack/ml/*_test.go
+status2=$?
+
+echo -e "\033[34;1mINFO:\033[0m Running tests: XPACK ML CRUD >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-ml-crud-junit.xml -- --tags=integration --timeout=1h -v ./xpack/ml-crud/*_test.go
+status3=$?
+
+if [[ $status1 == 0 && $status2 == 0 && $status3 == 0 ]]; then
+  exit 0
+else
+  exit 1
+fi
diff --git a/.ci/test-matrix.yml b/.ci/test-matrix.yml
new file mode 100644
index 0000000000..f5d6544748
--- /dev/null
+++ b/.ci/test-matrix.yml
@@ -0,0 +1,13 @@
+---
+
+STACK_VERSION:
+  - 7.16.3-SNAPSHOT
+
+GO_VERSION:
+  - 1-alpine
+
+TEST_SUITE:
+  - free
+  - platinum
+
+exclude: ~
diff --git a/.ci/tests-core.sh b/.ci/tests-core.sh
new file mode 100644
index 0000000000..5b875dbc5d
--- /dev/null
+++ b/.ci/tests-core.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+TIMEFORMAT="(Duration: %0lR)"
+
+echo -e "\033[1m>>>>> Cleaning up test files\033[0m"
+
+docker exec go-elasticsearch /bin/sh -c 'rm -rf esapi/test/*_test.go'
+docker exec go-elasticsearch /bin/sh -c 'rm -rf esapi/test/xpack'
+
+echo -e "\033[1m>>>>> Generating the API registry\033[0m"
+
+docker exec --workdir=/go-elasticsearch/internal/cmd/generate go-elasticsearch go get -u golang.org/x/tools/cmd/goimports
+docker exec --workdir=/go-elasticsearch/internal/cmd/generate --env PACKAGE_PATH=/go-elasticsearch/esapi go-elasticsearch go generate ./...
+
+echo -e "\033[1m>>>>> Generating the test files\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/internal/cmd/generate go-elasticsearch go run main.go apitests --output '/go-elasticsearch/esapi/test' --input '/elasticsearch-source/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/test/**/*.y*ml'
+
+echo -e "\033[1m>>>>> Running the tests\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/esapi/test go-elasticsearch /bin/sh -c 'gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-junit.xml -- -tags=integration -timeout=1h *_test.go'
+status=$?
+
+exit $status
diff --git a/.ci/tests-xpack.sh b/.ci/tests-xpack.sh
new file mode 100644
index 0000000000..9ced4cfb43
--- /dev/null
+++ b/.ci/tests-xpack.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+TIMEFORMAT="(Duration: %0lR)"
+
+echo -e "\033[1m>>>>> Cleaning up test files\033[0m"
+
+docker exec go-elasticsearch /bin/sh -c 'rm -rf esapi/test/*_test.go'
+docker exec go-elasticsearch /bin/sh -c 'rm -rf rm -rf esapi/test/ml*'
+
+echo -e "\033[1m>>>>> Generating the API registry\033[0m"
+
+docker exec --workdir=/go-elasticsearch/internal/cmd/generate go-elasticsearch go get -u golang.org/x/tools/cmd/goimports
+docker exec --workdir=/go-elasticsearch/internal/cmd/generate --env PACKAGE_PATH=/go-elasticsearch/esapi go-elasticsearch go generate ./...
+
+echo -e "\033[1m>>>>> Generating the test files\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/internal/cmd/generate go-elasticsearch go run main.go apitests --output '/go-elasticsearch/esapi/test/xpack' --input '/elasticsearch-source/elasticsearch/x-pack/plugin/src/test/resources/rest-api-spec/test/**/*.yml'
+
+time docker exec --tty --workdir=/go-elasticsearch/internal/cmd/generate go-elasticsearch go run main.go apitests --output '/go-elasticsearch/esapi/test/xpack' --input '/elasticsearch-source/elasticsearch/x-pack/plugin/src/test/resources/rest-api-spec/test/**/**/*.yml'
+
+docker exec go-elasticsearch mkdir -p esapi/test/xpack/ml
+docker exec go-elasticsearch mkdir -p esapi/test/xpack/ml-crud
+
+docker exec go-elasticsearch /bin/sh -c 'mv esapi/test/xpack/xpack_ml* esapi/test/xpack/ml/'
+docker exec go-elasticsearch mv esapi/test/xpack/ml/xpack_ml__jobs_crud_test.go esapi/test/xpack/ml-crud/
+
+echo -e "\033[1m>>>>> Running tests: XPACK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/esapi/test go-elasticsearch /bin/sh -c 'gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-junit.xml -- --tags=integration --timeout=1h -v xpack/*_test.go'
+status1=$?
+
+docker container rm --force --volumes es1 > /dev/null 2>&1
+make cluster-clean cluster version=elasticsearch:$ELASTICSEARCH_VERSION detach=true
+
+echo -e "\033[1m>>>>> Running tests: XPACK ML >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/esapi/test go-elasticsearch /bin/sh -c 'gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-ml-junit.xml -- --tags=integration --timeout=1h -v ./xpack/ml/*_test.go'
+status2=$?
+
+docker container rm --force --volumes es1 > /dev/null 2>&1
+make cluster-clean cluster version=elasticsearch:$ELASTICSEARCH_VERSION detach=true
+
+echo -e "\033[1m>>>>> Running tests: XPACK ML CRUD >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
+
+time docker exec --tty --workdir=/go-elasticsearch/esapi/test go-elasticsearch /bin/sh -c 'gotestsum --format=short-verbose --junitfile=$WORKSPACE/TEST-integration-api-xpack-ml-crud-junit.xml -- --tags=integration --timeout=1h -v ./xpack/ml-crud/*_test.go'
+status3=$?
+
+if [[ $status1 == 0 && $status2 == 0 || $status3 == 0 ]]; then
+  exit 0
+else
+  exit 1
+fi
diff --git a/.circleci/config.yml b/.circleci/config.yml
old mode 100755
new mode 100644
diff --git a/.codecov.yml b/.codecov.yml
old mode 100755
new mode 100644
diff --git a/.doc/connecting.asciidoc b/.doc/connecting.asciidoc
new file mode 100644
index 0000000000..e0e3c0dfaf
--- /dev/null
+++ b/.doc/connecting.asciidoc
@@ -0,0 +1,173 @@
+[[connecting]]
+== Connecting
+
+This page contains the information you need to connect and use the Client with 
+{es}.
+
+**On this page**
+
+* <<auth-reference, Authentication options>>
+* <<client-usage, Using the client>>
+
+[discrete]
+[[auth-reference]]
+=== Authentication
+
+This document contains code snippets to show you how to connect to various {es} 
+providers.
+
+
+[discrete]
+[[auth-basic]]
+==== Basic authentication
+
+To set the cluster endpoints, the username, and the password programatically, pass a configuration object to the `elasticsearch.NewClient()` function.
+
+[source,go]
+------------------------------------
+cfg := elasticsearch.Config{
+  Addresses: []string{
+    "http://localhost:9200",
+    "http://localhost:9201",
+  },
+  Username: "foo",
+  Password: "bar",
+}
+es, err := elasticsearch.NewClient(cfg)
+------------------------------------
+
+You can also include the username and password in the endpoint URL:
+
+```
+'https://username:password@localhost:9200'
+```
+
+
+[discrete]
+[[auth-ec]]
+==== Elastic Cloud
+
+If you are using https://www.elastic.co/cloud[Elastic Cloud], the client offers 
+an easy way to connect to it. You must pass the Cloud ID that you can find in 
+the cloud console and the corresponding API key.
+
+[source,go]
+------------------------------------
+cfg := elasticsearch.Config{
+		CloudID: "CLOUD_ID",
+		APIKey: "API_KEY"
+}
+es, err := elasticsearch.NewClient(cfg)
+------------------------------------
+
+[discrete]
+[[compatibility-mode]]
+=== Compatibility mode
+
+The {es} server version 8.0 is introducing a new compatibility mode that allows you a smoother upgrade experience from 7 to 8. In a nutshell, you can use the latest 7.x `go-elasticsearch` Elasticsearch client with an 8.x Elasticsearch server, giving more room to coordinate the upgrade of your codebase to the next major version.
+
+If you want to leverage this functionality, please make sure that you are using the latest 7.x `go-elasticsearch` client and set the environment variable `ELASTIC_CLIENT_APIVERSIONING` to `true` or the configuration option `config.EnableCompatibilityMode` in the client `Config`. The client is handling the rest internally. For every 8.0 and beyond `go-elasticsearch` client, you're all set! The compatibility mode is enabled by default.
+
+[discrete]
+[[client-usage]]
+=== Using the client
+
+The {es} package ties together two separate packages for calling the Elasticsearch APIs and transferring data over HTTP: `esapi` and `estransport`, respectively.
+
+Use the `elasticsearch.NewDefaultClient()` function to create the client with the default settings.
+
+[source,go]
+------------------------------------
+es, err := elasticsearch.NewDefaultClient()
+if err != nil {
+  log.Fatalf("Error creating the client: %s", err)
+}
+
+res, err := es.Info()
+if err != nil {
+  log.Fatalf("Error getting response: %s", err)
+}
+
+defer res.Body.Close()
+log.Println(res)
+------------------------------------
+
+[discrete]
+[[connecting-faas]]
+=== Using the Client in a Function-as-a-Service Environment
+
+This section illustrates the best practices for leveraging the {es} client in a Function-as-a-Service (FaaS) environment.
+The most influential optimization is to initialize the client outside of the function, the global scope.
+This practice does not only improve performance but also enables background functionality as – for example –
+https://www.elastic.co/blog/elasticsearch-sniffing-best-practices-what-when-why-how[sniffing].
+The following examples provide a skeleton for the best practices.
+
+[discrete]
+[[connecting-faas-gcp]]
+==== GCP Cloud Functions
+
+[source,go]
+----------------------------
+package httpexample
+
+import (
+	"github.com/elastic/go-elasticsearch/v7"
+)
+
+var client *elasticsearch.Client
+
+func init() {
+	var err error
+
+	... # Client configuration
+	client, err = elasticsearch.NewClient(cfg)
+	if err != nil {
+		log.Fatalf("elasticsearch.NewClient: %v", err)
+	}
+}
+
+func HttpExample(w http.ResponseWriter, r *http.Request) {
+	... # Client usage
+}
+
+----------------------------
+
+[discrete]
+[[connecting-faas-aws]]
+==== AWS Lambda
+
+[source,go]
+----------------------------
+package httpexample
+
+import (
+	"github.com/aws/aws-lambda-go/lambda"
+	"github.com/elastic/go-elasticsearch/v7"
+)
+
+var client *elasticsearch.Client
+
+func init() {
+	var err error
+
+	... # Client configuration
+	client, err = elasticsearch.NewClient(cfg)
+	if err != nil {
+		log.Fatalf("elasticsearch.NewClient: %v", err)
+	}
+}
+
+func HttpExample() {
+	... # Client usage
+}
+
+func main() {
+	lambda.Start(HttpExample)
+}
+----------------------------
+
+Resources used to assess these recommendations:
+
+* https://cloud.google.com/functions/docs/bestpractices/tips#use_global_variables_to_reuse_objects_in_future_invocations[GCP Cloud Functions: Tips & Tricks]
+* https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html[Best practices for working with AWS Lambda functions]
+* https://docs.aws.amazon.com/lambda/latest/operatorguide/global-scope.html[AWS Lambda: Comparing the effect of global scope]
diff --git a/.doc/index.asciidoc b/.doc/index.asciidoc
new file mode 100644
index 0000000000..a827f7d15f
--- /dev/null
+++ b/.doc/index.asciidoc
@@ -0,0 +1,11 @@
+= Elasticsearch Go Client
+
+:doctype:           book
+
+include::{asciidoc-dir}/../../shared/attributes.asciidoc[]
+
+include::overview.asciidoc[]
+
+include::installation.asciidoc[]
+
+include::connecting.asciidoc[]
diff --git a/.doc/installation.asciidoc b/.doc/installation.asciidoc
new file mode 100644
index 0000000000..3547b4bcee
--- /dev/null
+++ b/.doc/installation.asciidoc
@@ -0,0 +1,57 @@
+[[installation]]
+== Installation
+
+To install the 7.x version of the client, add the package to your `go.mod` file:
+
+[source,text]
+------------------------------------
+require github.com/elastic/go-elasticsearch/v7 7.16
+------------------------------------
+
+Or, clone the repository:
+
+[source,text]
+------------------------------------
+git clone --branch 7.16 https://github.com/elastic/go-elasticsearch.git $GOPATH/src/github
+------------------------------------
+
+To install another version, modify the path or the branch name accordingly. The 
+client major versions correspond to the {es} major versions.
+
+You can find a complete example of installation below:
+
+[source,text]
+------------------------------------
+mkdir my-elasticsearch-app && cd my-elasticsearch-app
+
+cat > go.mod <<-END
+  module my-elasticsearch-app
+
+  require github.com/elastic/go-elasticsearch/v8 main
+END
+
+cat > main.go <<-END
+  package main
+
+  import (
+    "log"
+
+    "github.com/elastic/go-elasticsearch/v8"
+  )
+
+  func main() {
+    es, _ := elasticsearch.NewDefaultClient()
+    log.Println(elasticsearch.Version)
+    log.Println(es.Info())
+  }
+END
+
+go run main.go
+------------------------------------
+
+
+[discrete]
+=== {es} Version Compatibility
+
+Language clients are forward compatible; meaning that clients support communicating with greater or equal minor versions of {es}.
+{es} language clients are only backwards compatible with default distributions and without guarantees made.
diff --git a/.doc/overview.asciidoc b/.doc/overview.asciidoc
new file mode 100644
index 0000000000..3723641d88
--- /dev/null
+++ b/.doc/overview.asciidoc
@@ -0,0 +1,67 @@
+[[overview]]
+== Overview
+
+This is the official Go client for {es}.
+
+Full documentation is hosted at 
+https://github.com/elastic/go-elasticsearch[GitHub]
+and https://godoc.org/github.com/elastic/go-elasticsearch[GoDoc]. This 
+documentation provides only an overview of features.
+
+[discrete]
+=== Features
+
+* One-to-one mapping with REST API.
+* Generalized, pluggable architecture.
+* Helpers for convenience.
+* Rich set of examples.
+
+
+[discrete]
+=== Usage
+
+[source,go]
+------------------------------------
+package main
+
+import (
+  "log"
+
+  "github.com/elastic/go-elasticsearch/v7"
+)
+
+func main() {
+  es, _ := elasticsearch.NewDefaultClient()
+  log.Println(es.Info())
+}
+------------------------------------
+
+[NOTE]
+Please have a look at the collection of comprehensive examples in the repository
+at https://github.com/elastic/go-elasticsearch/tree/master/_examples.
+
+
+[discrete]
+=== Resources
+
+* https://github.com/elastic/go-elasticsearch[Source Code]
+* https://godoc.org/github.com/elastic/go-elasticsearch[API Documentation]
+* https://github.com/elastic/go-elasticsearch/tree/master/_examples[Examples and Recipes]
+
+
+[discrete]
+=== License
+
+Copyright 2019 {es}.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/.dockerignore b/.dockerignore
old mode 100755
new mode 100644
diff --git a/.github/check-license-headers.sh b/.github/check-license-headers.sh
new file mode 100755
index 0000000000..042c5e9ac1
--- /dev/null
+++ b/.github/check-license-headers.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Licensed to Elasticsearch B.V. under one or more agreements.
+# Elasticsearch B.V. licenses this file to you under the Apache 2.0 License.
+# See the LICENSE file in the project root for more information.
+
+# Check that source code files in this repo have the appropriate license
+# header.
+
+if [ "$TRACE" != "" ]; then
+    export PS4='${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+    set -o xtrace
+fi
+set -o errexit
+set -o pipefail
+
+TOP=$(cd "$(dirname "$0")/.." >/dev/null && pwd)
+NLINES=$(wc -l .github/license-header.txt | awk '{print $1}')
+
+function check_license_header {
+    local f
+    f=$1
+    if ! diff .github/license-header.txt <(head -$NLINES "$f") >/dev/null; then
+        echo "check-license-headers: error: '$f' does not have required license header, see 'diff -u .github/license-header.txt <(head -$NLINES $f)'"
+        return 1
+    else
+        return 0
+    fi
+}
+
+
+cd "$TOP"
+nErrors=0
+for f in $(git ls-files | grep '\.go$'); do
+    if ! check_license_header $f; then
+        nErrors=$((nErrors+1))
+    fi
+done
+
+if [[ $nErrors -eq 0 ]]; then
+    exit 0
+else
+    exit 1
+fi
\ No newline at end of file
diff --git a/.github/license-header.txt b/.github/license-header.txt
new file mode 100644
index 0000000000..981aab5064
--- /dev/null
+++ b/.github/license-header.txt
@@ -0,0 +1,16 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000..d10594d653
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,36 @@
+name: Build
+
+on:
+  schedule:
+    - cron: '0 1 * * *'
+  push:
+    branches:
+      - github-actions
+      - main
+      - 7.16
+      - 6.x
+  pull_request:
+    branches:
+      - main
+      - 7.16
+      - 6.x
+
+env:
+  GITHUB_ACTIONS: true
+
+jobs:
+  lint:
+    name: Lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: '1.x' }
+      - name: Install dependencies
+        run: go get -u golang.org/x/lint/golint
+        env:
+          GOBIN: ${{ env.GOROOT }}/bin
+        shell: bash
+      - run: go version
+      - run: make lint
diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml
new file mode 100644
index 0000000000..8d916ba301
--- /dev/null
+++ b/.github/workflows/license.yml
@@ -0,0 +1,15 @@
+name: License headers
+
+on: [ pull_request ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Check license headers
+        run: |
+          ./.github/check-license-headers.sh
\ No newline at end of file
diff --git a/.github/workflows/test-api.yml b/.github/workflows/test-api.yml
new file mode 100644
index 0000000000..759da9c32d
--- /dev/null
+++ b/.github/workflows/test-api.yml
@@ -0,0 +1,74 @@
+name: API
+
+on:
+  schedule:
+    - cron: '0 2 * * *'
+
+env:
+  GITHUB_ACTIONS: true
+
+jobs:
+  test-free:
+    name: Free
+    env:
+      ELASTICSEARCH_VERSION: elasticsearch:7.x-SNAPSHOT
+      ELASTICSEARCH_URL: http://localhost:9200
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: '1.x' }
+      - run: go version
+      - name: Increase system limits
+        run: |
+          sudo swapoff -a
+          sudo sysctl -w vm.swappiness=1
+          sudo sysctl -w fs.file-max=262144
+          sudo sysctl -w vm.max_map_count=262144
+      - name: Launch Elasticsearch
+        run: |
+          docker pull --quiet docker.elastic.co/elasticsearch/${{ env.ELASTICSEARCH_VERSION }}
+          docker pull --quiet appropriate/curl
+          make cluster-clean cluster-update cluster detach=true version="${{ env.ELASTICSEARCH_VERSION }}"
+      - name: Download Elasticsearch source
+        run: |
+          curl -s ${{ env.ELASTICSEARCH_URL }} | jq -r '.version.build_hash' > elasticsearch_build_hash && cat elasticsearch_build_hash
+          curl -sSL --retry 3 -o elasticsearch-$(cat elasticsearch_build_hash).zip https://github.com/elastic/elasticsearch/archive/$(cat elasticsearch_build_hash).zip && \
+            unzip -q -o elasticsearch-$(cat elasticsearch_build_hash).zip '*.properties' '*.json' '*.yml' -d tmp && \
+            mv tmp/elasticsearch-$(cat elasticsearch_build_hash)* tmp/elasticsearch
+      - run: ELASTICSEARCH_BUILD_HASH=$(cat elasticsearch_build_hash) make gen-tests
+      - run: make test-api
+
+  test-platinum:
+      name: Platinum
+      env:
+        ELASTICSEARCH_VERSION: elasticsearch:7.x-SNAPSHOT
+        ELASTICSEARCH_URL: https://elastic:elastic@localhost:9200
+      runs-on: ubuntu-latest
+      steps:
+        - uses: actions/checkout@v2
+          with: { fetch-depth: 1 }
+        - uses: actions/setup-go@v2.1.3
+          with: { go-version: '1.x' }
+        - run: go version
+        - name: Increase system limits
+          run: |
+            sudo swapoff -a
+            sudo sysctl -w vm.swappiness=1
+            sudo sysctl -w fs.file-max=262144
+            sudo sysctl -w vm.max_map_count=262144
+        - name: Launch Elasticsearch
+          run: |
+            docker pull --quiet docker.elastic.co/elasticsearch/${{ env.ELASTICSEARCH_VERSION }}
+            docker pull --quiet appropriate/curl
+            make cluster-clean cluster-update cluster flavor=platinum detach=true version="${{ env.ELASTICSEARCH_VERSION }}"
+        - name: Download Elasticsearch source
+          run: |
+            curl -sSk ${{ env.ELASTICSEARCH_URL }}
+            curl -sSk ${{ env.ELASTICSEARCH_URL }} | jq -r '.version.build_hash' > elasticsearch_build_hash && cat elasticsearch_build_hash && \
+            curl -sSL --retry 3 -o elasticsearch-$(cat elasticsearch_build_hash).zip https://github.com/elastic/elasticsearch/archive/$(cat elasticsearch_build_hash).zip && \
+              unzip -q -o elasticsearch-$(cat elasticsearch_build_hash).zip '*.properties' '*.json' '*.yml' -d tmp && \
+              mv tmp/elasticsearch-$(cat elasticsearch_build_hash)* tmp/elasticsearch
+        - run: ELASTICSEARCH_BUILD_HASH=$(cat elasticsearch_build_hash) make gen-tests
+        - run: make test-api flavor=xpack
diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml
new file mode 100644
index 0000000000..2c35e6575e
--- /dev/null
+++ b/.github/workflows/test-integration.yml
@@ -0,0 +1,74 @@
+name: Integration
+
+on:
+  schedule:
+    - cron: '0 1 * * *'
+  push:
+    branches:
+      - github-actions
+      - main
+      - 7.16
+      - 6.x
+  pull_request:
+    branches:
+      - main
+      - 7.16
+      - 6.x
+
+env:
+  GITHUB_ACTIONS: true
+  ELASTICSEARCH_VERSION: elasticsearch:7.x-SNAPSHOT
+
+jobs:
+  test:
+    name: Tests
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: '1.x' }
+      - run: go version
+      - name: Increase system limits
+        run: |
+          sudo swapoff -a
+          sudo sysctl -w vm.swappiness=1
+          sudo sysctl -w fs.file-max=262144
+          sudo sysctl -w vm.max_map_count=262144
+      - name: Launch Elasticsearch
+        run: |
+          docker pull --quiet docker.elastic.co/elasticsearch/${{ env.ELASTICSEARCH_VERSION }}
+          docker pull --quiet appropriate/curl
+          make cluster-clean cluster-update cluster detach=true version="${{ env.ELASTICSEARCH_VERSION }}"
+      - run: make test-integ race=true
+      - uses: codecov/codecov-action@v1
+        with:
+          file: tmp/integration-client.cov
+          flags: integration
+
+  examples:
+    name: Examples
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: '1.x' }
+      - run: go version
+      - name: Increase system limits
+        run: |
+          sudo swapoff -a
+          sudo sysctl -w vm.swappiness=1
+          sudo sysctl -w fs.file-max=262144
+          sudo sysctl -w vm.max_map_count=262144
+      - name: Launch Elasticsearch
+        run: |
+          docker pull --quiet docker.elastic.co/elasticsearch/${{ env.ELASTICSEARCH_VERSION }}
+          docker pull --quiet appropriate/curl
+          make cluster-clean cluster-update cluster detach=true version="${{ env.ELASTICSEARCH_VERSION }}"
+      - name: Run setup
+        run: |
+          cd _examples/encoding && make setup
+        env:
+          GOBIN: ${{ env.GOROOT }}/bin
+      - run: make test-examples
diff --git a/.github/workflows/test-unit-tip.yml b/.github/workflows/test-unit-tip.yml
new file mode 100644
index 0000000000..fd97ba0ff6
--- /dev/null
+++ b/.github/workflows/test-unit-tip.yml
@@ -0,0 +1,37 @@
+name: Unit (tip)
+
+on:
+  schedule:
+    - cron: '0 1 * * *'
+
+env:
+  GITHUB_ACTIONS: true
+
+jobs:
+  test:
+    name: "go-HEAD @ ubuntu-latest"
+    runs-on: ubuntu-latest
+    steps:
+      # https://github.com/actions/setup-go/issues/21#issuecomment-565741980
+      - name: Install Go HEAD
+        run: |
+          export GOROOT_BOOTSTRAP=`go env GOROOT`
+          export GOROOT_FINAL=/go
+          export GOROOT=$HOME/gotip
+          mkdir $HOME/gotip
+          cd $HOME/gotip
+
+          curl -s 'https://go.googlesource.com/go/+/refs/heads/master?format=JSON' | awk '/"commit"/{print substr($2,2,40);exit}' >HEAD
+          awk '{printf("gotip-%s",substr($0,0,7))}' <HEAD >VERSION
+
+          curl -s -o go.tar.gz https://go.googlesource.com/go/+archive/`cat HEAD`.tar.gz
+          tar xfz go.tar.gz
+
+          cd src
+          bash make.bash
+          echo "GOROOT=$GOROOT" >> $GITHUB_ENV
+          echo "$GOROOT/bin" >> $GITHUB_PATH
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - run: go version
+      - run: make test-unit race=true
diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml
new file mode 100644
index 0000000000..3d83c778d0
--- /dev/null
+++ b/.github/workflows/test-unit.yml
@@ -0,0 +1,52 @@
+name: Unit
+
+on:
+  schedule:
+    - cron: '0 1 * * *'
+  push:
+    branches:
+      - github-actions
+      - main
+      - 7.16
+      - 6.x
+  pull_request:
+    branches:
+      - main
+      - 7.16
+      - 6.x
+
+env:
+  GITHUB_ACTIONS: true
+
+jobs:
+  test:
+    name: "Tests (${{ matrix.os }})"
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-latest, windows-latest, macOS-latest]
+        go: ['1.x']
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: "${{ matrix.go }}" }
+      - run: go version
+      - run: make test-unit race=true
+      - uses: codecov/codecov-action@v1
+        with:
+          file: tmp/unit.cov
+          flags: unit
+        if: matrix.os == 'ubuntu-latest'
+
+  bench:
+    name: Benchmarks
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+        with: { fetch-depth: 1 }
+      - uses: actions/setup-go@v2.1.3
+        with: { go-version: '1.x' }
+      - run: go version
+      - run: make test-bench
diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
index ed01357a26..7a915a0381
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 tmp/
 *.test
+
+#jetBrains editors
+.idea
\ No newline at end of file
diff --git a/.jenkins/jobs/elastic+go-elasticsearch+7.x.yml b/.jenkins/jobs/elastic+go-elasticsearch+7.x.yml
deleted file mode 100755
index 4a34e342e0..0000000000
--- a/.jenkins/jobs/elastic+go-elasticsearch+7.x.yml
+++ /dev/null
@@ -1,14 +0,0 @@
----
-- job:
-    name: elastic+go-elasticsearch+7.x
-    display-name: 'elastic / go-elasticsearch # 7.x'
-    description: Testing the go-elasticsearch 7.x branch.
-    junit_results: "*-junit.xml"
-    parameters:
-      - string:
-          name: branch_specifier
-          default: refs/heads/7.x
-          description: The Git branch specifier to build
-    triggers:
-      - github
-      - timed: '@daily'
diff --git a/.jenkins/run-tests b/.jenkins/run-tests
deleted file mode 100755
index e660d76733..0000000000
--- a/.jenkins/run-tests
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-set -eo pipefail
-
-function cleanup {
-  docker container rm --force --volumes es1 > /dev/null 2>&1 || true
-  docker container rm --force --volumes go-elasticsearch > /dev/null 2>&1 || true
-}
-
-trap cleanup EXIT
-
-echo -e "\033[1m>>>>> SETUP >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m"
-
-# Build the go-elasticsearch image
-docker build --file Dockerfile --tag elastic/go-elasticsearch .
-
-# Launch a single Elasticsearch node
-(make cluster detached=true)
-
-# Prepare the container
-docker run \
-  --name go-elasticsearch \
-  --network elasticsearch \
-  --env ELASTICSEARCH_URL=http://es1:9200 \
-  --env WORKSPACE=${WORKSPACE:-/workspace} \
-  --volume ${WORKSPACE:-workspace}:${WORKSPACE:-/workspace} \
-  --rm \
-  --detach \
-  elastic/go-elasticsearch sleep 3600
-docker cp .jenkins/tests.sh go-elasticsearch:/go-elasticsearch/tests.sh
-
-# Run the tests
-cmd="docker exec --tty go-elasticsearch /bin/sh /go-elasticsearch/tests.sh"
-
-if $cmd; then
-  echo -e "\n\033[32;1mSUCCESS\033[0m"
-  exit 0
-else
-  echo -e "\n\033[31;1mFAILURE\033[0m"
-  exit 1
-fi
diff --git a/.jenkins/test-matrix.yml b/.jenkins/test-matrix.yml
deleted file mode 100755
index 7a979a5f0d..0000000000
--- a/.jenkins/test-matrix.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-ELASTICSEARCH_VERSION:
-- 7.0.0-SNAPSHOT
-
-GO_VERSION:
-- 1-alpine
-
-exclude: ~
diff --git a/.jenkins/tests.sh b/.jenkins/tests.sh
deleted file mode 100755
index 9eb6c8d6b4..0000000000
--- a/.jenkins/tests.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env sh
-
-set -eo pipefail
-
-echo -e "\033[1m>>>>> CI >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m" && \
-echo -e "\033[1m>>>>> Waiting for Elasticsearch on $ELASTICSEARCH_URL...\033[0m" && \
-curl --max-time 120 --retry 120 --retry-delay 1 --retry-connrefused --show-error --silent --fail $ELASTICSEARCH_URL && \
-curl -s $ELASTICSEARCH_URL | jq -r '.version.build_hash' > .elasticsearch_build_hash && \
-export ES_BUILD_HASH=$(cat .elasticsearch_build_hash) && \
-echo -e "\033[1m>>>>> Downloading Elasticsearch repository @ $ES_BUILD_HASH...\033[0m" && \
-echo "curl -sSL -o elasticsearch-$ES_BUILD_HASH.zip https://github.com/elastic/elasticsearch/archive/$ES_BUILD_HASH.zip" && \
-(rm -rf tmp/elasticsearch) || true && (mkdir -p tmp || true) && \
-curl --retry 3 -sSL -o elasticsearch-$ES_BUILD_HASH.zip https://github.com/elastic/elasticsearch/archive/$ES_BUILD_HASH.zip && \
-unzip -q -o elasticsearch-$ES_BUILD_HASH.zip '*.properties' '*.json' '*.y*ml' -d tmp && \
-mv tmp/elasticsearch-$ES_BUILD_HASH* tmp/elasticsearch && \
-echo -e "\033[1m>>>>> Generating the API registry\033[0m" && \
-(cd internal/cmd/generate && ELASTICSEARCH_BUILD_HASH=$ES_BUILD_HASH PACKAGE_PATH=$PWD/../../../esapi go generate -v ./... 2> /dev/null) && \
-echo -e "\033[1m>>>>> Generating the test files\033[0m" && \
-(cd internal/cmd/generate && ELASTICSEARCH_BUILD_HASH=$ES_BUILD_HASH go run main.go tests --input "$PWD/../../../tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/test/**/*.y*ml" --output="$PWD/../../../esapi/test") && \
-echo -e "\033[1m>>>>> Running the tests\033[0m" && \
-(cd esapi/test && gotestsum --format=short-verbose --junitfile="$WORKSPACE/TEST-integration-api-junit.xml" -- -tags='integration' -timeout=1h ./...) ; exitstatus=$? ; \
-echo -e "\n\033[1m<<<<< Finished API integration tests for $ES_BUILD_HASH\033[0m" ; \
-echo -e "Junit Report: $(ls $WORKSPACE/TEST-integration-api-junit.xml)" && \
-exit $exitstatus
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100755
index 6f25e45523..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,172 +0,0 @@
-dist: xenial
-
-language: go
-
-services:
-  - docker
-
-branches:
-  only:
-    - master
-    - travis
-
-install: true
-
-matrix:
-  fast_finish: true
-  allow_failures:
-    - os: windows
-  include:
-    - name: Unit Tests | Linux, go:stable, gomod=on
-      os: linux
-      go: stable
-      env: GO111MODULE=on TEST_SUITE=unit
-      script:
-        - go mod verify
-        - go build -v ./...
-        - make lint
-        - gotestsum --format=short-verbose --junitfile=/tmp/unit-junit.xml -- -coverprofile=/tmp/unit.cov -tags='unit' -timeout=1h -v ./...
-      after_script:
-        - test -f /tmp/unit.cov && bash <(curl -s https://codecov.io/bash) -f /tmp/unit.cov
-
-    - name: Unit Tests | Linux, go:stable, gomod=off
-      os: linux
-      go: stable
-      env: GO111MODULE=off TEST_SUITE=unit
-      before_install:
-        - go get -u golang.org/x/lint/golint
-        - go get -u gotest.tools/gotestsum
-      install:
-        - go get -v ./...
-      script:
-        - go build -v ./...
-        - make lint
-        - gotestsum --format=short-verbose --junitfile=/tmp/unit-junit.xml -- -tags='unit' -timeout=1h -v ./...
-
-    - name: Unit Tests | OS X, go:stable, gomod=on
-      os: osx
-      go: stable
-      env: GO111MODULE=on TEST_SUITE=unit
-      script:
-        - go mod verify
-        - go build -v ./...
-        - gotestsum --format=short-verbose --junitfile=/tmp/unit-junit.xml -- --tags='unit' --timeout=1h -v ./...
-
-    - name: Unit Tests | Windows, go:stable, gomod=on
-      os: windows
-      go: stable
-      env: GO111MODULE=on TEST_SUITE=unit
-      script:
-        - go mod verify
-        - go build -v ./...
-        - gotestsum --format=short-verbose --junitfile=/tmp/unit-junit.xml -- -tags='unit' -timeout=1h -v ./...
-
-    - name: Unit Tests | Linux, go:master, gomod=on
-      os: linux
-      go: master
-      env: GO111MODULE=on TEST_SUITE=unit
-      script:
-        - go mod verify
-        - go build -v ./...
-        - make lint
-        - gotestsum --format=short-verbose --junitfile=/tmp/unit-junit.xml -- -tags='unit' -timeout=1h -v ./...
-
-    - name: Unit Tests | Docker/Linux, golang:1-alpine
-      os: linux
-      env: TEST_SUITE=unit
-      before_install: true
-      script:
-        - grep 'FROM' Dockerfile
-        - docker build --file Dockerfile --tag elastic/go-elasticsearch .
-        - echo $(($(docker image inspect -f '{{.Size}}' elastic/go-elasticsearch)/(1000*1000)))MB
-        - docker run -ti elastic/go-elasticsearch make lint
-        - docker run -ti elastic/go-elasticsearch make test
-
-    - name: Integration Tests | Linux, go:stable
-      os: linux
-      go: stable
-      env: GO111MODULE=on TEST_SUITE=integration-client
-      before_script:
-        - docker pull docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-SNAPSHOT
-        - docker network inspect elasticsearch > /dev/null || docker network create elasticsearch;
-        - |
-            docker run \
-              --name es-integration-client \
-              --network elasticsearch \
-              --env "cluster.name=es-integration-client" \
-              --env "discovery.type=single-node" \
-              --env "bootstrap.memory_lock=true" \
-              --env "cluster.routing.allocation.disk.threshold_enabled=false" \
-              --env ES_JAVA_OPTS="-Xms1g -Xmx1g" \
-              --volume es-integration-client-data:/usr/share/elasticsearch/data \
-              --publish 9200:9200 \
-              --ulimit nofile=65536:65536 \
-              --ulimit memlock=-1:-1 \
-              --detach \
-              --rm \
-              docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-SNAPSHOT
-        - docker run --network elasticsearch --rm appropriate/curl --max-time 120 --retry 120 --retry-delay 1 --retry-connrefused --show-error --silent http://es-integration-client:9200
-      script:
-        - gotestsum --format=short-verbose --junitfile=/tmp/integration-report.xml -- -race -cover -coverprofile=/tmp/integration-client.cov -tags='integration' -timeout=1h github.com/elastic/go-elasticsearch
-      after_script:
-        - test -f /tmp/integration-client.cov && bash <(curl -s https://codecov.io/bash) -f /tmp/integration-client.cov
-
-
-    - name: Integration Tests, API | Linux, go:stable
-      os: linux
-      go: stable
-      env: GO111MODULE=on TEST_SUITE=integration-api
-      before_script:
-        - docker pull docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-SNAPSHOT
-        - docker network inspect elasticsearch > /dev/null || docker network create elasticsearch;
-        - |
-            docker run \
-              --name es-integration-api \
-              --network elasticsearch \
-              --env "cluster.name=es-integration-api" \
-              --env "discovery.type=single-node" \
-              --env "bootstrap.memory_lock=true" \
-              --env "cluster.routing.allocation.disk.threshold_enabled=false" \
-              --env "node.attr.testattr=test" \
-              --env "path.repo=/tmp" \
-              --env "repositories.url.allowed_urls=http://snapshot.test*" \
-              --env ES_JAVA_OPTS="-Xms1g -Xmx1g" \
-              --volume es-integration-api-data:/usr/share/elasticsearch/data \
-              --publish 9200:9200 \
-              --ulimit nofile=65536:65536 \
-              --ulimit memlock=-1:-1 \
-              --detach \
-              --rm \
-              docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-SNAPSHOT
-        - docker run --network elasticsearch --rm appropriate/curl --max-time 120 --retry 120 --retry-delay 1 --retry-connrefused --show-error --silent http://es-integration-api:9200
-      script:
-        - curl -s http://localhost:9200 | jq -r '.version.build_hash' > .elasticsearch_build_hash && cat .elasticsearch_build_hash
-        # ------ Download Elasticsearch -----------------------------------------------------------
-        - echo -e "\e[33;1mDownload Elasticsearch Git source @ $(cat .elasticsearch_build_hash)\e[0m" && echo -en 'travis_fold:start:script.dl_es_src\\r'
-        - echo https://github.com/elastic/elasticsearch/archive/$(cat .elasticsearch_build_hash).zip
-        - |
-            curl -sSL --retry 3 -o elasticsearch-$(cat .elasticsearch_build_hash).zip https://github.com/elastic/elasticsearch/archive/$(cat .elasticsearch_build_hash).zip && \
-            unzip -q -o elasticsearch-$(cat .elasticsearch_build_hash).zip '*.properties' '*.json' '*.yml' -d /tmp && \
-            mv /tmp/elasticsearch-$(cat .elasticsearch_build_hash)* /tmp/elasticsearch
-        - echo -en 'travis_fold:end:script.dl_es_src'
-        # ------ Generate API registry ------------------------------------------------------------
-        - echo -e "\e[33;1mGenerate API registry\e[0m" && echo -en 'travis_fold:start:script.gen_api_reg\\r\n'
-        - cd ${TRAVIS_HOME}/gopath/src/github.com/elastic/go-elasticsearch/internal/cmd/generate && ELASTICSEARCH_BUILD_HASH=$(cat ../../../.elasticsearch_build_hash) PACKAGE_PATH=${TRAVIS_HOME}/gopath/src/github.com/elastic/go-elasticsearch/esapi go generate -v ./...
-        - echo -en 'travis_fold:end:script.gen_api_reg'
-        # ------ Generate Go test files -----------------------------------------------------------
-        - echo -e "\e[33;1mGenerate Go test files\e[0m" && echo -en 'travis_fold:start:script.gen_test_files\\r'
-        - cd ${TRAVIS_HOME}/gopath/src/github.com/elastic/go-elasticsearch/internal/cmd/generate && ELASTICSEARCH_BUILD_HASH=$(cat ../../../.elasticsearch_build_hash) go run main.go tests --input '/tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/test/**/*.yml' --output=../../../esapi/test
-        - echo -en 'travis_fold:end:script.gen_test_files'
-        # ------ Run tests -----------------------------------------------------------------------
-        - cd ${TRAVIS_HOME}/gopath/src/github.com/elastic/go-elasticsearch/esapi/test && time gotestsum --format=short-verbose --junitfile=/tmp/integration-api-report.xml -- -coverpkg=github.com/elastic/go-elasticsearch/esapi -coverprofile=/tmp/integration-api.cov -tags='integration' -timeout=1h ./...
-      after_script:
-        - test -f /tmp/integration-api.cov && bash <(curl -s https://codecov.io/bash) -f /tmp/integration-api.cov
-
-before_install:
-    - GO111MODULE=off go get -u golang.org/x/lint/golint
-    - GO111MODULE=off go get -u gotest.tools/gotestsum
-
-script: echo "TODO > test $TEST_SUITE ($TRAVIS_OS_NAME)"
-
-notifications:
-  email: true
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100755
index 92d2934ab0..0000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,22 +0,0 @@
-# $ docker build --file Dockerfile --tag elastic/go-elasticsearch .
-#
-# $ docker run -it --network elasticsearch --volume $PWD/tmp:/tmp:rw --rm elastic/go-elasticsearch gotestsum --format=short-verbose --junitfile=/tmp/integration-junit.xml -- --cover --coverprofile=/tmp/integration-coverage.out --tags='integration' -v ./...
-#
-
-ARG  VERSION=1-alpine
-FROM golang:${VERSION}
-
-RUN apk add --no-cache --quiet make curl git jq && \
-    go get -u golang.org/x/lint/golint && \
-    curl -sSL --retry 3 --retry-connrefused https://github.com/gotestyourself/gotestsum/releases/download/v0.3.2/gotestsum_0.3.2_linux_amd64.tar.gz | tar -xz -C /usr/local/bin gotestsum
-
-VOLUME ["/tmp"]
-
-ENV CGO_ENABLED=0
-ENV TERM xterm-256color
-
-WORKDIR /go-elasticsearch
-COPY . .
-
-RUN go mod download && go mod vendor && \
-    cd internal/cmd/generate && go mod download && go mod vendor
diff --git a/LICENSE b/LICENSE
old mode 100755
new mode 100644
diff --git a/Makefile b/Makefile
old mode 100755
new mode 100644
index 1bf6a503ea..5b41adaa9c
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,10 @@
+SHELL := /bin/bash
+
+ELASTICSEARCH_DEFAULT_BUILD_VERSION = "7.16.3-SNAPSHOT"
+
 ##@ Test
 test-unit:  ## Run unit tests
-	@echo "\033[2m→ Running unit tests...\033[0m"
+	@printf "\033[2m→ Running unit tests...\033[0m\n"
 ifdef race
 	$(eval testunitargs += "-race")
 endif
@@ -16,195 +20,455 @@ endif
 test: test-unit
 
 test-integ:  ## Run integration tests
-	@echo "\033[2m→ Running integration tests...\033[0m"
+	@printf "\033[2m→ Running integration tests...\033[0m\n"
+	$(eval testintegtags += "integration")
+ifdef multinode
+	$(eval testintegtags += "multinode")
+endif
 ifdef race
 	$(eval testintegargs += "-race")
 endif
-	$(eval testintegargs += "-cover" "-coverprofile=tmp/integration-client.cov" "-tags='integration'" "-timeout=1h" "github.com/elastic/go-elasticsearch" "github.com/elastic/go-elasticsearch/estransport")
+	$(eval testintegargs += "-cover" "-coverprofile=tmp/integration-client.cov" "-tags='$(testintegtags)'" "-timeout=1h")
 	@mkdir -p tmp
 	@if which gotestsum > /dev/null 2>&1 ; then \
 		echo "gotestsum --format=short-verbose --junitfile=tmp/integration-report.xml --" $(testintegargs); \
-		gotestsum --format=short-verbose --junitfile=tmp/integration-report.xml -- $(testintegargs); \
+		gotestsum --format=short-verbose --junitfile=tmp/integration-report.xml -- $(testintegargs) "."; \
+		gotestsum --format=short-verbose --junitfile=tmp/integration-report.xml -- $(testintegargs) "./estransport" "./esapi" "./esutil"; \
 	else \
-		echo "go test -v" $(testintegargs); \
-		go test -v $(testintegargs); \
+		echo "go test -v" $(testintegargs) "."; \
+		go test -v $(testintegargs) "./estransport" "./esapi" "./esutil"; \
 	fi;
 
 test-api:  ## Run generated API integration tests
-	@echo "\033[2m→ Running API integration tests...\033[0m"
+	@mkdir -p tmp
 ifdef race
 	$(eval testapiargs += "-race")
 endif
-	$(eval testapiargs += "-cover" "-coverpkg=github.com/elastic/go-elasticsearch/esapi" "-coverprofile=$(PWD)/tmp/integration-api.cov" "-tags='integration'" "-timeout=1h" "./...")
-	@mkdir -p tmp
-	@if which gotestsum > /dev/null 2>&1 ; then \
-		echo "cd esapi/test && gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml --" $(testapiargs); \
-		cd esapi/test && gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml -- $(testapiargs); \
-	else \
-		echo "go test -v" $(testapiargs); \
-		cd esapi/test && go test -v $(testapiargs); \
-	fi;
+	$(eval testapiargs += "-cover" "-coverpkg=github.com/elastic/go-elasticsearch/v7/esapi" "-coverprofile=$(PWD)/tmp/integration-api.cov" "-tags='integration'" "-timeout=1h")
+ifdef flavor
+else
+	$(eval flavor='free')
+endif
+	@printf "\033[2m→ Running API integration tests for [$(flavor)]...\033[0m\n"
+ifeq ($(flavor), platinum)
+	@{ \
+		set -e ; \
+		trap "test -d .git && git checkout --quiet $(PWD)/esapi/test/go.mod" INT TERM EXIT; \
+		export ELASTICSEARCH_URL='https://elastic:elastic@localhost:9200' && \
+		if which gotestsum > /dev/null 2>&1 ; then \
+			cd esapi/test && \
+			go mod download && \
+				gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml -- $(testapiargs) $(PWD)/esapi/test/xpack/*_test.go && \
+				gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml -- $(testapiargs) $(PWD)/esapi/test/xpack/ml/*_test.go && \
+				gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml -- $(testapiargs) $(PWD)/esapi/test/xpack/ml-crud/*_test.go; \
+		else \
+			echo "go test -v" $(testapiargs); \
+			cd esapi/test && \
+			go mod download && \
+				go test -v $(testapiargs) $(PWD)/esapi/test/xpack/*_test.go && \
+				go test -v $(testapiargs) $(PWD)/esapi/test/xpack/ml/*_test.go && \
+				go test -v $(testapiargs) $(PWD)/esapi/test/xpack/ml-crud/*_test.go;  \
+		fi; \
+	}
+else
+	$(eval testapiargs += $(PWD)/esapi/test/*_test.go)
+	@{ \
+		set -e ; \
+		trap "test -d .git && git checkout --quiet $(PWD)/esapi/test/go.mod" INT TERM EXIT; \
+		if which gotestsum > /dev/null 2>&1 ; then \
+			cd esapi/test && \
+			go mod download && \
+			gotestsum --format=short-verbose --junitfile=$(PWD)/tmp/integration-api-report.xml -- $(testapiargs); \
+		else \
+			echo "go test -v" $(testapiargs); \
+			cd esapi/test && \
+			go mod download && \
+			go test -v $(testapiargs); \
+		fi; \
+	}
+endif
 
 test-bench:  ## Run benchmarks
-	@echo "\033[2m→ Running benchmarks...\033[0m"
+	@printf "\033[2m→ Running benchmarks...\033[0m\n"
 	go test -run=none -bench=. -benchmem ./...
 
 test-examples: ## Execute the _examples
-	@echo "\033[2m→ Testing the examples...\033[0m"
+	@printf "\033[2m→ Testing the examples...\033[0m\n"
 	@{ \
 		set -e ; \
+		trap "test -d .git && git checkout --quiet _examples/**/go.mod" INT TERM EXIT; \
+		for d in _examples/*/; do \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\n"; \
+			printf "\033[1mUpdating dependencies for $$d\033[0m\n"; \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
+			(cd $$d && go mod download && make setup) || \
+			( \
+				printf "\033[31m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
+				printf "\033[31;1m⨯ ERROR\033[0m\n"; \
+				false; \
+			); \
+	    done; \
+	    \
 		for f in _examples/*.go; do \
-			echo "\033[2m────────────────────────────────────────────────────────────────────────────────"; \
-			echo "\033[1m$$f\033[0m"; \
-			echo "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\n"; \
+			printf "\033[1m$$f\033[0m\n"; \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
 			(go run $$f && true) || \
 			( \
-				echo "\033[31m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
-				echo "\033[31;1m⨯ ERROR\033[0m"; \
+				printf "\033[31m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
+				printf "\033[31;1m⨯ ERROR\033[0m\n"; \
 				false; \
 			); \
 		done; \
 		\
 		for f in _examples/*/; do \
-			echo "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
-			echo "\033[1m$$f\033[0m"; \
-			echo "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
+			printf "\033[1m$$f\033[0m\n"; \
+			printf "\033[2m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
 			(cd $$f && make test && true) || \
 			( \
-				echo "\033[31m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
-				echo "\033[31;1m⨯ ERROR\033[0m"; \
+				printf "\033[31m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
+				printf "\033[31;1m⨯ ERROR\033[0m\n"; \
 				false; \
 			); \
 		done; \
-		echo "\033[32m────────────────────────────────────────────────────────────────────────────────\033[0m"; \
+		printf "\033[32m────────────────────────────────────────────────────────────────────────────────\033[0m\n"; \
 		\
-		echo "\033[32;1mSUCCESS\033[0m"; \
+		printf "\033[32;1mSUCCESS\033[0m\n"; \
 	}
 
 test-coverage:  ## Generate test coverage report
-	@echo "\033[2m→ Generating test coverage report...\033[0m"
+	@printf "\033[2m→ Generating test coverage report...\033[0m\n"
 	@go tool cover -html=tmp/unit.cov -o tmp/coverage.html
 	@go tool cover -func=tmp/unit.cov | 'grep' -v 'esapi/api\.' | sed 's/github.com\/elastic\/go-elasticsearch\///g'
-	@echo "--------------------------------------------------------------------------------\nopen tmp/coverage.html\n"
+	@printf "\033[0m--------------------------------------------------------------------------------\nopen tmp/coverage.html\n\n\033[0m"
 
 ##@ Development
 lint:  ## Run lint on the package
-	@echo "\033[2m→ Running lint...\033[0m"
+	@printf "\033[2m→ Running lint...\033[0m\n"
 	go vet github.com/elastic/go-elasticsearch/...
 	go list github.com/elastic/go-elasticsearch/... | 'grep' -v internal | xargs golint -set_exit_status
+	@{ \
+		set -e ; \
+		trap "test -d ../../../.git && git checkout --quiet go.mod" INT TERM EXIT; \
+		echo "cd internal/build/ && go vet ./..."; \
+		cd "internal/build/" && go mod tidy && go mod download && go vet ./...; \
+	}
+
 
 apidiff: ## Display API incompabilities
 	@if ! command -v apidiff > /dev/null; then \
-		echo "\033[31;1mERROR: apidiff not installed\033[0m"; \
-		echo "go get -u github.com/go-modules-by-example/apidiff"; \
-		echo "\033[2m→ https://github.com/go-modules-by-example/index/blob/master/019_apidiff/README.md\033[0m\n"; \
+		printf "\033[31;1mERROR: apidiff not installed\033[0m\n"; \
+		printf "go get -u github.com/go-modules-by-example/apidiff\n"; \
+		printf "\033[2m→ https://github.com/go-modules-by-example/index/blob/master/019_apidiff/README.md\033[0m\n\n"; \
 		false; \
 	fi;
 	@rm -rf tmp/apidiff-OLD tmp/apidiff-NEW
 	@git clone --quiet --local .git/ tmp/apidiff-OLD
 	@mkdir -p tmp/apidiff-NEW
 	@tar -c --exclude .git --exclude tmp --exclude cmd . | tar -x -C tmp/apidiff-NEW
-	@echo "\033[2m→ Running apidiff...\033[0m"
-	@echo "tmp/apidiff-OLD/esapi tmp/apidiff-NEW/esapi"
+	@printf "\033[2m→ Running apidiff...\033[0m\n"
+	@pritnf "tmp/apidiff-OLD/esapi tmp/apidiff-NEW/esapi\n"
 	@{ \
 		set -e ; \
 		output=$$(apidiff tmp/apidiff-OLD/esapi tmp/apidiff-NEW/esapi); \
-		echo "\n$$output\n"; \
-		if echo $$output | grep -e 'incompatible' -; then \
-			echo "\n\033[31;1mFAILURE\033[0m\n"; \
+		printf "\n$$output\n\n"; \
+		if echo $$output | grep -i -e 'incompatible' - > /dev/null 2>&1; then \
+			printf "\n\033[31;1mFAILURE\033[0m\n\n"; \
 			false; \
 		else \
-			echo "\033[32;1mSUCCESS\033[0m"; \
+			printf "\033[32;1mSUCCESS\033[0m\n"; \
+		fi; \
+	}
+
+backport: ## Backport one or more commits from master into version branches
+ifeq ($(origin commits), undefined)
+	@echo "Missing commit(s), exiting..."
+	@exit 2
+endif
+ifndef branches
+	$(eval branches_list = '7.16' '6.x' '5.x')
+else
+	$(eval branches_list = $(shell echo $(branches) | tr ',' ' ') )
+endif
+	$(eval commits_list = $(shell echo $(commits) | tr ',' ' '))
+	@printf "\033[2m→ Backporting commits [$(commits)]\033[0m\n"
+	@{ \
+		set -e -o pipefail; \
+		for commit in $(commits_list); do \
+			git show --pretty='%h | %s' --no-patch $$commit; \
+		done; \
+		echo ""; \
+		for branch in $(branches_list); do \
+			printf "\033[2m→ $$branch\033[0m\n"; \
+			git checkout $$branch; \
+			for commit in $(commits_list); do \
+				git cherry-pick -x $$commit; \
+			done; \
+			git status --short --branch; \
+			echo ""; \
+		done; \
+		printf "\033[2m→ Push updates to Github:\033[0m\n"; \
+		for branch in $(branches_list); do \
+			echo "git push --verbose origin $$branch"; \
+		done; \
+	}
+
+release: ## Release a new version to Github
+	$(eval branch = $(shell git rev-parse --abbrev-ref HEAD))
+	$(eval current_version = $(shell cat internal/version/version.go | sed -Ee 's/const Client = "(.*)"/\1/' | tail -1))
+	@printf "\033[2m→ [$(branch)] Current version: $(current_version)...\033[0m\n"
+ifndef version
+	@printf "\033[31m[!] Missing version argument, exiting...\033[0m\n"
+	@exit 2
+endif
+ifeq ($(version), "")
+	@printf "\033[31m[!] Empty version argument, exiting...\033[0m\n"
+	@exit 2
+endif
+	@printf "\033[2m→ [$(branch)] Creating version $(version)...\033[0m\n"
+	@{ \
+		set -e -o pipefail; \
+		cp internal/version/version.go internal/version/version.go.OLD && \
+		cat internal/version/version.go.OLD | sed -e 's/Client = ".*"/Client = "$(version)"/' > internal/version/version.go && \
+		go vet internal/version/version.go && \
+		go fmt internal/version/version.go && \
+		git diff --color-words internal/version/version.go | tail -n 1; \
+	}
+	@{ \
+		set -e -o pipefail; \
+		printf "\033[2m→ Commit and create Git tag? (y/n): \033[0m\c"; \
+		read continue; \
+		if [[ $$continue == "y" ]]; then \
+			git add internal/version/version.go && \
+			git commit --no-status --quiet --message "Release $(version)" && \
+			git tag --annotate v$(version) --message 'Release $(version)'; \
+			printf "\033[2m→ Push `git show --pretty='%h (%s)' --no-patch HEAD` to Github:\033[0m\n\n"; \
+			printf "\033[1m  git push origin HEAD && git push origin v$(version)\033[0m\n\n"; \
+			mv internal/version/version.go.OLD internal/version/version.go && \
+			git add internal/version/version.go && \
+			original_version=`cat internal/version/version.go | sed -ne 's;^const Client = "\(.*\)"$$;\1;p'` && \
+			git commit --no-status --quiet --message "Update version to $$original_version"; \
+			printf "\033[2m→ Version updated to [$$original_version].\033[0m\n\n"; \
+		else \
+			echo "Aborting..."; \
+			rm internal/version/version.go.OLD; \
+			exit 1; \
 		fi; \
 	}
 
 godoc: ## Display documentation for the package
-	@echo "\033[2m→ Generating documentation...\033[0m"
-	@echo "open http://localhost:6060/pkg/github.com/elastic/go-elasticsearch/\n"
-	mkdir -p /tmp/tmpgoroot/doc
-	rm -rf /tmp/tmpgopath/src/github.com/elastic/go-elasticsearch
-	mkdir -p /tmp/tmpgopath/src/github.com/elastic/go-elasticsearch
-	tar -c --exclude='.git' --exclude='tmp' . | tar -x -C /tmp/tmpgopath/src/github.com/elastic/go-elasticsearch
-	GOROOT=/tmp/tmpgoroot/ GOPATH=/tmp/tmpgopath/ godoc -http=localhost:6060 -play
+	@printf "\033[2m→ Generating documentation...\033[0m\n"
+	@echo "* http://localhost:6060/pkg/github.com/elastic/go-elasticsearch/v7"
+	@echo "* http://localhost:6060/pkg/github.com/elastic/go-elasticsearch/v7/esapi"
+	@echo "* http://localhost:6060/pkg/github.com/elastic/go-elasticsearch/v7/estransport"
+	@echo "* http://localhost:6060/pkg/github.com/elastic/go-elasticsearch/v7/esutil"
+	@printf "\n"
+	godoc --http=localhost:6060 --play
 
 cluster: ## Launch an Elasticsearch cluster with Docker
-	$(eval version ?= "elasticsearch-oss:7.0.0-SNAPSHOT")
+	$(eval version ?= "elasticsearch:7.x-SNAPSHOT")
+	$(eval flavor ?= "core")
+	$(eval elasticsearch_url = "http://es1:9200")
+
+ifdef ELASTICSEARCH_BUILD_VERSION
+	$(eval version ?= "elasticsearch:"${ELASTICSEARCH_BUILD_VERSION})
+else
+	$(eval version ?= "elasticsearch:"${ELASTICSEARCH_DEFAULT_BUILD_VERSION})
+endif
+
 ifeq ($(origin nodes), undefined)
 	$(eval nodes = 1)
 endif
-	@echo "\033[2m→ Launching" $(nodes) "node(s) of" $(version) "...\033[0m"
+	@printf "\033[2m→ Launching %d node(s) of %s...\033[0m\n" $(nodes) $(version)
 ifeq ($(shell test $(nodes) && test $(nodes) -gt 1; echo $$?),0)
-	$(eval detached ?= "true")
+	$(eval detach ?= "true")
 else
-	$(eval detached ?= "false")
+	$(eval detach ?= "false")
 endif
-	@docker network inspect elasticsearch > /dev/null || docker network create elasticsearch;
+
+ifeq ($(flavor), platinum)
+	$(eval elasticsearch_url = "https://elastic:elastic@es1:9200")
+	$(eval xpack_env += --env "ELASTIC_PASSWORD=elastic")
+	$(eval xpack_env += --env "xpack.license.self_generated.type=trial")
+	$(eval xpack_env += --env "xpack.security.enabled=true")
+	$(eval xpack_env += --env "xpack.security.http.ssl.enabled=true")
+	$(eval xpack_env += --env "xpack.security.http.ssl.key=certs/testnode.key")
+	$(eval xpack_env += --env "xpack.security.http.ssl.certificate=certs/testnode.crt")
+	$(eval xpack_env += --env "xpack.security.http.ssl.certificate_authorities=certs/ca.crt")
+	$(eval xpack_env += --env "xpack.security.transport.ssl.enabled=true")
+	$(eval xpack_env += --env "xpack.security.transport.ssl.verification_mode=certificate")
+	$(eval xpack_env += --env "xpack.security.transport.ssl.key=certs/testnode.key")
+	$(eval xpack_env += --env "xpack.security.transport.ssl.certificate=certs/testnode.crt")
+	$(eval xpack_env += --env "xpack.security.transport.ssl.certificate_authorities=certs/ca.crt")
+	$(eval xpack_volumes += --volume "$(PWD)/.ci/certs/testnode.crt:/usr/share/elasticsearch/config/certs/testnode.crt")
+	$(eval xpack_volumes += --volume "$(PWD)/.ci/certs/testnode.key:/usr/share/elasticsearch/config/certs/testnode.key")
+	$(eval xpack_volumes += --volume "$(PWD)/.ci/certs/ca.crt:/usr/share/elasticsearch/config/certs/ca.crt")
+endif
+	@docker network inspect elasticsearch > /dev/null 2>&1 || docker network create elasticsearch;
 	@{ \
 		for n in `seq 1 $(nodes)`; do \
+			if [[ -z "$$port" ]]; then \
+				hostport=$$((9199+$$n)); \
+			else \
+				hostport=$$port; \
+			fi; \
 			docker run \
 				--name "es$$n" \
 				--network elasticsearch \
 				--env "node.name=es$$n" \
 				--env "cluster.name=go-elasticsearch" \
 				--env "cluster.initial_master_nodes=es1" \
+				--env "discovery.seed_hosts=es1" \
 				--env "cluster.routing.allocation.disk.threshold_enabled=false" \
 				--env "bootstrap.memory_lock=true" \
 				--env "node.attr.testattr=test" \
 				--env "path.repo=/tmp" \
 				--env "repositories.url.allowed_urls=http://snapshot.test*" \
 				--env ES_JAVA_OPTS="-Xms1g -Xmx1g" \
+				$(xpack_env) \
 				--volume `echo $(version) | tr -C "[:alnum:]" '-'`-node-$$n-data:/usr/share/elasticsearch/data \
-				--publish $$((9199+$$n)):9200 \
+				$(xpack_volumes) \
+				--publish $$hostport:9200 \
 				--ulimit nofile=65536:65536 \
 				--ulimit memlock=-1:-1 \
-				--detach=$(detached) \
+				--detach=$(detach) \
 				--rm \
 				docker.elastic.co/elasticsearch/$(version); \
 		done \
 	}
+ifdef detach
 	@{ \
-		if [[ "$(detached)" == "true" ]]; then \
-			echo "\033[2m→ Waiting for the cluster...\033[0m"; \
-			docker run --network elasticsearch --rm appropriate/curl --max-time 120 --retry 120 --retry-delay 1 --retry-connrefused --show-error --silent http://es1:9200; \
-		fi \
+		printf "\033[2m→ Waiting for the cluster on $(elasticsearch_url)...\033[0m\n"; \
+		docker run --network elasticsearch --rm appropriate/curl --max-time 120 --retry 120 --retry-delay 1 --retry-connrefused --show-error --silent --insecure $(elasticsearch_url); \
+		output="\033[2m→ Cluster ready; to remove containers:"; \
+		output="$$output docker rm -f"; \
+		for n in `seq 1 $(nodes)`; do \
+			output="$$output es$$n"; \
+		done; \
+		printf "$$output\033[0m\n"; \
 	}
+endif
 
 cluster-update: ## Update the Docker image
-	$(eval version ?= "elasticsearch-oss:7.0.0-SNAPSHOT")
-	@echo "\033[2m→ Updating the Docker image...\033[0m"
+ifdef ELASTICSEARCH_BUILD_VERSION
+	$(eval version ?= "elasticsearch:"${ELASTICSEARCH_BUILD_VERSION})
+else
+	$(eval version ?= "elasticsearch:"${ELASTICSEARCH_DEFAULT_BUILD_VERSION})
+endif
+	@printf "\033[2m→ Updating the Docker image...\033[0m\n"
 	@docker pull docker.elastic.co/elasticsearch/$(version);
 
 cluster-clean: ## Remove unused Docker volumes and networks
-	@echo "\033[2m→ Cleaning up Docker assets...\033[0m"
+	@printf "\033[2m→ Cleaning up Docker assets...\033[0m\n"
 	docker volume prune --force
 	docker network prune --force
 
 docker: ## Build the Docker image and run it
-	docker build --file Dockerfile --tag elastic/go-elasticsearch .
+	docker build --file .ci/Dockerfile --tag elastic/go-elasticsearch .
 	docker run -it --network elasticsearch --volume $(PWD)/tmp:/tmp:rw,delegated --rm elastic/go-elasticsearch
 
 ##@ Generator
 gen-api:  ## Generate the API package from the JSON specification
-	@echo "\033[2m→ Generating API package from specification...\033[0m"
-	$(eval input  ?= tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/api/*.json)
+	$(eval input  ?= tmp/rest-api-spec)
 	$(eval output ?= esapi)
 ifdef debug
 	$(eval args += --debug)
 endif
-ifdef skip-registry
-	$(eval args += --skip-registry)
+ifdef ELASTICSEARCH_BUILD_VERSION
+	$(eval version = $(ELASTICSEARCH_BUILD_VERSION))
+else
+	$(eval version = $(ELASTICSEARCH_DEFAULT_BUILD_VERSION))
+endif
+ifdef ELASTICSEARCH_BUILD_HASH
+	$(eval build_hash = $(ELASTICSEARCH_BUILD_HASH))
+else
+	$(eval build_hash = $(shell cat tmp/elasticsearch.json | jq ".projects.elasticsearch.commit_hash"))
 endif
-	cd internal/cmd/generate && go run main.go source --input '$(PWD)/$(input)' --output '$(PWD)/$(output)' $(args)
+	@printf "\033[2m→ Generating API package from specification ($(version):$(build_hash))...\033[0m\n"
+	@{ \
+		set -e; \
+		trap "test -d .git && git checkout --quiet $(PWD)/internal/build/go.mod" INT TERM EXIT; \
+		export ELASTICSEARCH_BUILD_VERSION=$(version) && \
+		export ELASTICSEARCH_BUILD_HASH=$(build_hash) && \
+		cd internal/build && \
+		go run main.go apisource --input '$(PWD)/$(input)/api/*.json' --output '$(PWD)/$(output)' $(args) && \
+		go run main.go apistruct --output '$(PWD)/$(output)'; \
+	}
 
 gen-tests:  ## Generate the API tests from the YAML specification
-	@echo "\033[2m→ Generating API tests from specification...\033[0m"
-	$(eval input  ?= tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/test/**/*.y*ml)
+	$(eval input  ?= tmp/rest-api-spec)
 	$(eval output ?= esapi/test)
 ifdef debug
 	$(eval args += --debug)
 endif
-	rm -rf esapi/test/*_test.go
-	cd internal/cmd/generate && go generate ./... && go run main.go tests --input '$(PWD)/$(input)' --output '$(PWD)/$(output)' $(args)
+ifdef ELASTICSEARCH_BUILD_VERSION
+	$(eval version = $(ELASTICSEARCH_BUILD_VERSION))
+else
+	$(eval version = $(ELASTICSEARCH_DEFAULT_BUILD_VERSION))
+endif
+ifdef ELASTICSEARCH_BUILD_HASH
+	$(eval build_hash = $(ELASTICSEARCH_BUILD_HASH))
+else
+	$(eval build_hash = $(shell cat tmp/elasticsearch.json | jq ".projects.elasticsearch.commit_hash"))
+endif
+	@printf "\033[2m→ Generating API tests from specification ($(version):$(build_hash))...\033[0m\n"
+	@{ \
+		set -e; \
+		trap "test -d .git && git checkout --quiet $(PWD)/internal/cmd/generate/go.mod" INT TERM EXIT; \
+		export ELASTICSEARCH_BUILD_VERSION=$(version) && \
+		export ELASTICSEARCH_BUILD_HASH=$(build_hash) && \
+		rm -rf $(output)/*_test.go && \
+		rm -rf $(output)/xpack && \
+		cd internal/build && \
+		go get golang.org/x/tools/cmd/goimports && \
+		go generate ./... && \
+		go run main.go apitests --input '$(PWD)/$(input)/test/free/**/*.y*ml' --output '$(PWD)/$(output)' $(args) && \
+		go run main.go apitests --input '$(PWD)/$(input)/test/platinum/**/*.yml' --output '$(PWD)/$(output)/xpack' $(args) && \
+		mkdir -p '$(PWD)/esapi/test/xpack/ml' && \
+		mkdir -p '$(PWD)/esapi/test/xpack/ml-crud' && \
+		mv $(PWD)/esapi/test/xpack/xpack_ml* $(PWD)/esapi/test/xpack/ml/ && \
+		mv $(PWD)/esapi/test/xpack/ml/xpack_ml__jobs_crud_test.go $(PWD)/esapi/test/xpack/ml-crud/; \
+	}
+
+gen-docs:  ## Generate the skeleton of documentation examples
+	$(eval input  ?= tmp/alternatives_report.json)
+	$(eval update ?= no)
+	@{ \
+		set -e; \
+		trap "test -d .git && git checkout --quiet $(PWD)/internal/cmd/generate/go.mod" INT TERM EXIT; \
+		if [[ $(update) == 'yes' ]]; then \
+			printf "\033[2m→ Updating the alternatives_report.json file\033[0m\n" && \
+			curl -s https://raw.githubusercontent.com/elastic/built-docs/master/raw/en/elasticsearch/reference/master/alternatives_report.json > tmp/alternatives_report.json; \
+		fi; \
+		printf "\033[2m→ Generating Go source files from Console input in [$(input)]\033[0m\n" && \
+		( cd '$(PWD)/internal/cmd/generate' && \
+			go run main.go examples src --debug --input='$(PWD)/$(input)' --output='$(PWD)/.doc/examples/' \
+		) && \
+		( cd '$(PWD)/.doc/examples/src' && \
+			if which gotestsum > /dev/null 2>&1 ; then \
+				gotestsum --format=short-verbose; \
+			else \
+				go test -v $(testunitargs); \
+			fi; \
+		) && \
+		printf "\n\033[2m→ Generating ASCIIDoc files from Go source\033[0m\n" && \
+		( cd '$(PWD)/internal/build' && \
+			go run main.go examples doc --debug --input='$(PWD)/.doc/examples/src/' --output='$(PWD)/.doc/examples/' \
+		) \
+	}
+
+download-specs: ## Download the latest specs for the specified Elasticsearch version
+	$(eval output ?= tmp)
+	@mkdir -p tmp
+	@{ \
+		set -e; \
+		printf "\n\033[2m→ Downloading latest Elasticsearch specs for version [$(ELASTICSEARCH_DEFAULT_BUILD_VERSION)]\033[0m\n" && \
+		rm -rf $(output)/rest-api-spec && \
+		rm -rf $(output)/elasticsearch.json && \
+		cd internal/build && \
+		go run main.go download-spec --output '$(PWD)/$(output)'; \
+	}
 
 ##@ Other
 #------------------------------------------------------------------------------
@@ -213,4 +477,4 @@ help:  ## Display help
 #------------- <https://suva.sh/posts/well-documented-makefiles> --------------
 
 .DEFAULT_GOAL := help
-.PHONY: help apidiff cluster cluster-clean cluster-update coverage docker examples gen-api gen-tests godoc lint test test-api test-bench test-integ test-unit
+.PHONY: help apidiff backport cluster cluster-clean cluster-update coverage docker examples gen-api gen-tests godoc lint release test test-api test-bench test-integ test-unit
diff --git a/README.md b/README.md
old mode 100755
new mode 100644
index 5fdcd380e1..02b8fee657
--- a/README.md
+++ b/README.md
@@ -2,34 +2,52 @@
 
 The official Go client for [Elasticsearch](https://www.elastic.co/products/elasticsearch).
 
-[![GoDoc](https://godoc.org/github.com/elastic/go-elasticsearch?status.svg)](http://godoc.org/github.com/elastic/go-elasticsearch)
-[![Travis-CI](https://travis-ci.org/elastic/go-elasticsearch.svg?branch=master)](https://travis-ci.org/elastic/go-elasticsearch)
+[![GoDoc](https://godoc.org/github.com/elastic/go-elasticsearch?status.svg)](https://pkg.go.dev/github.com/elastic/go-elasticsearch/v7)
 [![Go Report Card](https://goreportcard.com/badge/github.com/elastic/go-elasticsearch)](https://goreportcard.com/report/github.com/elastic/go-elasticsearch)
-[![codecov.io](https://codecov.io/github/elastic/go-elasticsearch/coverage.svg?branch=master)](https://codecov.io/gh/elastic/go-elasticsearch?branch=master)
+[![codecov.io](https://codecov.io/github/elastic/go-elasticsearch/coverage.svg?branch=main)](https://codecov.io/gh/elastic/go-elasticsearch?branch=main)
+[![Build](https://github.com/elastic/go-elasticsearch/workflows/Build/badge.svg)](https://github.com/elastic/go-elasticsearch/actions?query=branch%3Amain)
+[![Unit](https://github.com/elastic/go-elasticsearch/workflows/Unit/badge.svg)](https://github.com/elastic/go-elasticsearch/actions?query=branch%3Amain)
+[![Integration](https://github.com/elastic/go-elasticsearch/workflows/Integration/badge.svg)](https://github.com/elastic/go-elasticsearch/actions?query=branch%3Amain)
+[![API](https://github.com/elastic/go-elasticsearch/workflows/API/badge.svg)](https://github.com/elastic/go-elasticsearch/actions?query=branch%3Amain)
 
-## Caveats
+## Compatibility
 
-We encourage you to try the package in your projects, just keep these caveats in mind, please:
+Language clients are forward compatible; meaning that clients support communicating with greater or equal minor versions of Elasticsearch.
+Elasticsearch language clients are only backwards compatible with default distributions and without guarantees made.
 
-* **This is a work in progress.** Not all the planned features, standard in official Elasticsearch clients — retries on failures, auto-discovering nodes, ... — are implemented yet.
-* **There are no guarantees on API stability.** Though the public APIs have been designed very carefully, they can change in a backwards-incompatible way depending on further exploration and user feedback.
-* **The `master` branch targets Elasticsearch 7.x.** The [6.x](https://github.com/elastic/go-elasticsearch/tree/6.x) and [5.x](https://github.com/elastic/go-elasticsearch/tree/5.x) branches are compatible with the respective major versions of Elasticsearch; proper compatibility matrix and release tags will be added soon.
+When using Go modules, include the version in the import path, and specify either an explicit version or a branch:
 
-<!-- ----------------------------------------------------------------------------------------------- -->
+    require github.com/elastic/go-elasticsearch/v7 7.16
+    require github.com/elastic/go-elasticsearch/v7 7.0.0
 
-## Installation
+It's possible to use multiple versions of the client in a single project:
+
+    // go.mod
+    github.com/elastic/go-elasticsearch/v6 6.x
+    github.com/elastic/go-elasticsearch/v7 7.16
+
+    // main.go
+    import (
+      elasticsearch6 "github.com/elastic/go-elasticsearch/v6"
+      elasticsearch7 "github.com/elastic/go-elasticsearch/v7"
+    )
+    // ...
+    es6, _ := elasticsearch6.NewDefaultClient()
+    es7, _ := elasticsearch7.NewDefaultClient()
+
+The `main` branch of the client is compatible with the current `master` branch of Elasticsearch.
 
-Install the package with `go get`:
+<!-- ----------------------------------------------------------------------------------------------- -->
 
-    go get -u github.com/elastic/go-elasticsearch
+## Installation
 
-Or, add the package to your `go.mod` file:
+Add the package to your `go.mod` file:
 
-    require github.com/elastic/go-elasticsearch master
+    require github.com/elastic/go-elasticsearch/v8 main
 
 Or, clone the repository:
 
-    git clone https://github.com/elastic/go-elasticsearch.git && cd go-elasticsearch
+    git clone --branch main https://github.com/elastic/go-elasticsearch.git $GOPATH/src/github.com/elastic/go-elasticsearch
 
 A complete example:
 
@@ -39,7 +57,7 @@ mkdir my-elasticsearch-app && cd my-elasticsearch-app
 cat > go.mod <<-END
   module my-elasticsearch-app
 
-  require github.com/elastic/go-elasticsearch master
+  require github.com/elastic/go-elasticsearch/v8 main
 END
 
 cat > main.go <<-END
@@ -48,11 +66,12 @@ cat > main.go <<-END
   import (
     "log"
 
-    "github.com/elastic/go-elasticsearch"
+    "github.com/elastic/go-elasticsearch/v7"
   )
 
   func main() {
     es, _ := elasticsearch.NewDefaultClient()
+    log.Println(elasticsearch.Version)
     log.Println(es.Info())
   }
 END
@@ -80,6 +99,7 @@ if err != nil {
   log.Fatalf("Error getting response: %s", err)
 }
 
+defer res.Body.Close()
 log.Println(res)
 
 // [200 OK] {
@@ -88,10 +108,12 @@ log.Println(res)
 // ...
 ```
 
+> NOTE: It is _critical_ to both close the response body _and_ to consume it, in order to re-use persistent TCP connections in the default HTTP transport. If you're not interested in the response body, call `io.Copy(ioutil.Discard, res.Body)`.
+
 When you export the `ELASTICSEARCH_URL` environment variable,
 it will be used to set the cluster endpoint(s). Separate multiple adresses by a comma.
 
-To set the cluster endpoint(s) programatically, pass them in the configuration object
+To set the cluster endpoint(s) programatically, pass a configuration object
 to the `elasticsearch.NewClient()` function.
 
 ```golang
@@ -100,36 +122,57 @@ cfg := elasticsearch.Config{
     "http://localhost:9200",
     "http://localhost:9201",
   },
+  // ...
 }
 es, err := elasticsearch.NewClient(cfg)
-// ...
 ```
 
-To configure the HTTP settings, pass a [`http.Transport`](https://golang.org/pkg/net/http/#Transport)
-object in the configuration object (the values are for illustrative purposes only).
+To set the username and password, include them in the endpoint URL,
+or use the corresponding configuration options.
+
+```golang
+cfg := elasticsearch.Config{
+  // ...
+  Username: "foo",
+  Password: "bar",
+}
+```
+
+To set a custom certificate authority used to sign the certificates of cluster nodes,
+use the `CACert` configuration option.
+
+```golang
+cert, _ := ioutil.ReadFile(*cacert)
+
+cfg := elasticsearch.Config{
+  // ...
+  CACert: cert,
+}
+```
+
+To configure other HTTP settings, pass an [`http.Transport`](https://golang.org/pkg/net/http/#Transport)
+object in the configuration object.
 
 ```golang
 cfg := elasticsearch.Config{
   Transport: &http.Transport{
     MaxIdleConnsPerHost:   10,
     ResponseHeaderTimeout: time.Second,
-    DialContext:           (&net.Dialer{Timeout: time.Second}).DialContext,
     TLSClientConfig: &tls.Config{
       MinVersion: tls.VersionTLS11,
       // ...
     },
+    // ...
   },
 }
-
-es, err := elasticsearch.NewClient(cfg)
-// ...
 ```
 
 See the [`_examples/configuration.go`](_examples/configuration.go) and
 [`_examples/customization.go`](_examples/customization.go) files for
 more examples of configuration and customization of the client.
+See the [`_examples/security`](_examples/security) for an example of a security configuration.
 
-The following example demonstrates a more complex usage. It fetches the Elasticsearch version from the cluster, indexes a couple of documents concurrently, and prints the search results, using a light wrapper around the response body.
+The following example demonstrates a more complex usage. It fetches the Elasticsearch version from the cluster, indexes a couple of documents concurrently, and prints the search results, using a lightweight wrapper around the response body.
 
 ```golang
 // $ go run _examples/main.go
@@ -137,6 +180,7 @@ The following example demonstrates a more complex usage. It fetches the Elastics
 package main
 
 import (
+  "bytes"
   "context"
   "encoding/json"
   "log"
@@ -144,8 +188,8 @@ import (
   "strings"
   "sync"
 
-  "github.com/elastic/go-elasticsearch"
-  "github.com/elastic/go-elasticsearch/esapi"
+  "github.com/elastic/go-elasticsearch/v7"
+  "github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 func main() {
@@ -171,6 +215,7 @@ func main() {
   if err != nil {
     log.Fatalf("Error getting response: %s", err)
   }
+  defer res.Body.Close()
   // Check response status
   if res.IsError() {
     log.Fatalf("Error: %s", res.String())
@@ -192,11 +237,17 @@ func main() {
     go func(i int, title string) {
       defer wg.Done()
 
-      // Set up the request object directly.
+      // Build the request body.
+      var b strings.Builder
+      b.WriteString(`{"title" : "`)
+      b.WriteString(title)
+      b.WriteString(`"}`)
+
+      // Set up the request object.
       req := esapi.IndexRequest{
         Index:      "test",
         DocumentID: strconv.Itoa(i + 1),
-        Body:       strings.NewReader(`{"title" : "` + title + `"}`),
+        Body:       strings.NewReader(b.String()),
         Refresh:    "true",
       }
 
@@ -227,23 +278,36 @@ func main() {
 
   // 3. Search for the indexed documents
   //
-  // Use the helper methods of the client.
+  // Build the request body.
+  var buf bytes.Buffer
+  query := map[string]interface{}{
+    "query": map[string]interface{}{
+      "match": map[string]interface{}{
+        "title": "test",
+      },
+    },
+  }
+  if err := json.NewEncoder(&buf).Encode(query); err != nil {
+    log.Fatalf("Error encoding query: %s", err)
+  }
+
+  // Perform the search request.
   res, err = es.Search(
     es.Search.WithContext(context.Background()),
     es.Search.WithIndex("test"),
-    es.Search.WithBody(strings.NewReader(`{"query" : { "match" : { "title" : "test" } }}`)),
+    es.Search.WithBody(&buf),
     es.Search.WithTrackTotalHits(true),
     es.Search.WithPretty(),
   )
   if err != nil {
-    log.Fatalf("ERROR: %s", err)
+    log.Fatalf("Error getting response: %s", err)
   }
   defer res.Body.Close()
 
   if res.IsError() {
     var e map[string]interface{}
     if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
-      log.Fatalf("error parsing the response body: %s", err)
+      log.Fatalf("Error parsing the response body: %s", err)
     } else {
       // Print the response status and error information.
       log.Fatalf("[%s] %s: %s",
@@ -287,13 +351,25 @@ func main() {
 As you see in the example above, the `esapi` package allows to call the Elasticsearch APIs in two distinct ways: either by creating a struct, such as `IndexRequest`, and calling its `Do()` method by passing it a context and the client, or by calling the `Search()` function on the client directly, using the option functions such as `WithIndex()`. See more information and examples in the
 [package documentation](https://godoc.org/github.com/elastic/go-elasticsearch/esapi).
 
-The `estransport` package handles the transfer of data to and from Elasticsearch. At the moment, the implementation is really minimal: it only round-robins across the configured cluster endpoints. In future, more features — retrying failed requests, ignoring certain status codes, auto-discovering nodes in the cluster, and so on — will be added.
+The `estransport` package handles the transfer of data to and from Elasticsearch, including retrying failed requests, keeping a connection pool, discovering cluster nodes and logging.
+
+Read more about the client internals and usage in the following blog posts:
+
+* https://www.elastic.co/blog/the-go-client-for-elasticsearch-introduction
+* https://www.elastic.co/blog/the-go-client-for-elasticsearch-configuration-and-customization
+* https://www.elastic.co/blog/the-go-client-for-elasticsearch-working-with-data
+
+<!-- ----------------------------------------------------------------------------------------------- -->
+
+## Helpers
+
+The `esutil` package provides convenience helpers for working with the client. At the moment, it provides the `esutil.JSONReader()` and the `esutil.BulkIndexer` helpers.
 
 <!-- ----------------------------------------------------------------------------------------------- -->
 
 ## Examples
 
-The **[`_examples`](./_examples)** folder contains a number of recipes and comprehensive examples to get you started with the client, including configuration and customization of the client, mocking the transport for unit tests, embedding the client in a custom type, building queries, performing requests, and parsing the responses.
+The **[`_examples`](./_examples)** folder contains a number of recipes and comprehensive examples to get you started with the client, including configuration and customization of the client, using a custom certificate authority (CA) for security (TLS), mocking the transport for unit tests, embedding the client in a custom type, building queries, performing requests individually and in bulk, and parsing the responses.
 
 <!-- ----------------------------------------------------------------------------------------------- -->
 
diff --git a/_examples/README.md b/_examples/README.md
old mode 100755
new mode 100644
index 6f7bf591c0..89de9c5c6f
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -10,25 +10,30 @@ The [**`logging`**](./logging) directory contains examples for using the default
 
 ## Bulk
 
-The [**`bulk`**](./bulk) directory contains a comprehensive example for using the _Bulk_ API.
+The [**`bulk`**](./bulk) directory contains a comprehensive example of using the _Bulk_ API.
+
+## Encoding
+
+The [**`encoding`**](./encoding) directory contains examples of using third-party packages
+and client helper methods for a more efficient encoding and decoding of the request and response bodies.
 
 ## Fast HTTP
 
 The [**`fasthttp`**](./fasthttp) directory contains a demonstration of replacing the default client transport with an HTTP client from the [`github.com/valyala/fasthttp`](https://godoc.org/github.com/valyala/fasthttp) package.
 
-## Google Cloud Functions
+## Instrumentation
 
-The [**`cloudfunction`**](./cloudfunction) directory contains a simple web service for checking Elasticsearch cluster status.
+The [**`instrumentation`**](./instrumentation) directory contains recipes for instrumenting the client with the OpenCensus and Elastic APM packages.
 
-## XKCD Search
+## Extension
 
-The [**`xkcdsearch`**](./xkcdsearch) directory contains a command-line utility for indexing and searching an archive of [xkcd.com](https://xkcd.com) artworks.
+The [**`extension`**](./extension) directory contains an example of extending the client APIs, for example
+to support custom endpoints installed by a plugin.
 
-## Encoding
+## Google Cloud Functions
 
-The [**`encoding`**](./encoding) directory contains examples of using third-party packages
-for a more efficient encoding and decoding request/response JSON payloads.
+The [**`cloudfunction`**](./cloudfunction) directory contains a simple web service for checking Elasticsearch cluster status.
 
-## Instrumentation
+## XKCD Search
 
-The [**`instrumentation`**](./instrumentation) directory contains recipes for instrumenting the client.
+The [**`xkcdsearch`**](./xkcdsearch) directory contains a command-line utility for indexing and searching an archive of [xkcd.com](https://xkcd.com) artworks.
diff --git a/_examples/bulk/.gitignore b/_examples/bulk/.gitignore
new file mode 100644
index 0000000000..1d9ba24cdd
--- /dev/null
+++ b/_examples/bulk/.gitignore
@@ -0,0 +1,2 @@
+go.sum
+*_easyjson.go
diff --git a/_examples/bulk/Makefile b/_examples/bulk/Makefile
index e30aeade76..5a38f60966 100644
--- a/_examples/bulk/Makefile
+++ b/_examples/bulk/Makefile
@@ -1,6 +1,23 @@
 GO_TEST_CMD = $(if $(shell which richgo),richgo test,go test)
 
-test:  ## Run tests
-	go run bulk.go
+test: test-default test-indexer
 
-.PHONY: test
+test-default:
+	go run default.go
+
+test-indexer:
+	go run indexer.go
+
+test-benchmarks: clean setup
+	cd benchmarks && go run benchmarks.go
+
+setup:
+	@go get -u github.com/mailru/easyjson/...
+	@go mod download github.com/dustin/go-humanize
+	@go mod download github.com/cenkalti/backoff/v4
+	cd benchmarks && go mod download && go mod download github.com/mailru/easyjson && go generate ./model
+
+clean:
+	@rm -f benchmarks/model/*_easyjson.go
+
+.PHONY: test test-default test-indexer test-benchmarks setup clean
diff --git a/_examples/bulk/README.md b/_examples/bulk/README.md
index 59d4e299a2..bb915239d3 100644
--- a/_examples/bulk/README.md
+++ b/_examples/bulk/README.md
@@ -1,8 +1,8 @@
 # Example: Bulk Indexing
 
-## `bulk.go`
+## `default.go`
 
-The [`bulk.go`](bulk.go) example demonstrates how to properly operate the Elasticsearch's
+The [`default.go`](default.go) example demonstrates how to properly operate the Elasticsearch's
 [Bulk API]([https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html]).
 
 The example intentionally doesn't use any abstractions or helper functions, to
@@ -17,13 +17,43 @@ demonstrate the low-level mechanics of working with the Bulk API:
 * printing a report.
 
 ```bash
-go run bulk.go -count=100000 -batch=25000
-
-# > Generated 100000 articles
-# > Batch 1  of 4
-# > Batch 2  of 4
-# > Batch 3  of 4
-# > Batch 4  of 4
-# ================================================================================
-# Sucessfuly indexed [100000] documents in 8.02s (12469 docs/sec)
+go run default.go -count=100000 -batch=25000
+
+# Bulk: documents [100,000] batch size [25,000]
+# ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
+# → Generated 100,000 articles
+# → Sending batch [1/4] [2/4] [3/4] [4/4]
+# ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+# Sucessfuly indexed [100,000] documents in 3.423s (29,214 docs/sec)
+```
+
+## `indexer.go`
+
+The [`indexer.go`](indexer.go) example demonstrates how to use the [`esutil.BulkIndexer`](../esutil/bulk_indexer.go) helper for efficient indexing in parallel.
+
+```bash
+go run indexer.go -count=100000 -flush=1000000
+
+# BulkIndexer: documents [100,000] workers [8] flush [1.0 MB]
+# ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
+# → Generated 100,000 articles
+# ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+# Sucessfuly indexed [100,000] documents in 1.909s (52,383 docs/sec)
+```
+
+The helper allows you to `Add()` bulk indexer items, and flushes each batch based on the configured threshold.
+
+```golang
+indexer, _ := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{})
+indexer.Add(
+	context.Background(),
+	esutil.BulkIndexerItem{
+		Action: "index",
+		Body:   strings.NewReader(`{"title":"Test"}`),
+	})
+indexer.Close(context.Background())
 ```
+
+Please refer to the [`benchmarks`](benchmarks) folder for performance tests with different types of payload.
+
+See the [`kafka`](kafka) folder for an end-to-end example of using the bulk helper for indexing data from a Kafka topic.
diff --git a/_examples/bulk/benchmarks/README.md b/_examples/bulk/benchmarks/README.md
new file mode 100644
index 0000000000..7b3c67824b
--- /dev/null
+++ b/_examples/bulk/benchmarks/README.md
@@ -0,0 +1,124 @@
+# Bulk Indexer Benchmarks
+
+The [`benchmarks.go`](benchmarks.go) file executes end-to-end benchmarks for `esutil.NewBulkIndexer`. It allows to configure indexer parameters, index settings, number of runs. See `go run benchmarks.go --help` for an overview of configuration options:
+
+```
+go run benchmarks.go --help
+  -count int
+    	Number of documents to generate (default 100000)
+  -dataset string
+    	Dataset to use for indexing (default "small")
+  -debug
+    	Enable logging output
+  -easyjson
+    	Use mailru/easyjson for JSON decoding
+  -fasthttp
+    	Use valyala/fasthttp for HTTP transport
+  -flush value
+    	Flush threshold in bytes (default 3MB)
+  -index string
+    	Index name (default "test-bulk-benchmarks")
+  -mockserver
+    	Measure added, not flushed items
+  -replicas int
+    	Number of index replicas (default 0)
+  -runs int
+    	Number of runs (default 10)
+  -shards int
+    	Number of index shards (default 3)
+  -wait duration
+    	Wait duration between runs (default 1s)
+  -warmup int
+    	Number of warmup runs (default 3)
+  -workers int
+    	Number of indexer workers (default 4)
+```
+
+Before running the benchmarks, install `easyjson` and generate the auxiliary files:
+
+```
+go mod download
+go get -u github.com/mailru/easyjson/...
+grep '~/go/bin' ~/.profile || echo 'export PATH=$PATH:~/go/bin' >> ~/.profile && source ~/.profile
+go generate -v ./model
+```
+
+## Small Document
+
+The [`small`](data/small/document.json) dataset uses a small document (126B).
+
+```
+ELASTICSEARCH_URL=http://server:9200 go run benchmarks.go --dataset=small --count=1_000_000 --flush=2MB --shards=5 --replicas=0 --fasthttp=true --easyjson=true
+small: run [10x] warmup [3x] shards [5] replicas [0] workers [8] flush [2.0 MB] wait [1s] fasthttp easyjson
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+   1) add=1M  flush=1M  fail=0  reqs=52 dur=3.58s   279,173 docs/sec
+   2) add=1M  flush=1M  fail=0  reqs=52 dur=3.52s   284,090 docs/sec
+   3) add=1M  flush=1M  fail=0  reqs=52 dur=3.45s   289,351 docs/sec
+   4) add=1M  flush=1M  fail=0  reqs=52 dur=3.49s   286,123 docs/sec
+   5) add=1M  flush=1M  fail=0  reqs=52 dur=3.47s   287,852 docs/sec
+   6) add=1M  flush=1M  fail=0  reqs=52 dur=3.47s   288,184 docs/sec
+   7) add=1M  flush=1M  fail=0  reqs=52 dur=3.54s   282,246 docs/sec
+   8) add=1M  flush=1M  fail=0  reqs=52 dur=3.47s   288,101 docs/sec
+   9) add=1M  flush=1M  fail=0  reqs=52 dur=3.54s   282,485 docs/sec
+  10) add=1M  flush=1M  fail=0  reqs=52 dur=3.46s   288,350 docs/sec
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+docs/sec: min [279,173] max [289,351] mean [286,987]
+```
+
+## HTTP Log Event
+
+The [`httplog`](data/httplog/document.json) dataset uses a bigger document (2.5K), corresponding to a log event gathered by [Filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-nginx.html) from Nginx.
+
+```
+ELASTICSEARCH_URL=http://server:9200 go run benchmarks.go --dataset=httplog --count=1_000_000 --flush=3MB --shards=5 --replicas=0 --fasthttp=true --easyjson=true
+httplog: run [10x] warmup [3x] shards [5] replicas [0] workers [8] flush [3.0 MB] wait [1s] fasthttp easyjson
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+   1) add=1M   flush=1M fail=0   reqs=649 dur=19.93s  50,165 docs/sec
+   2) add=1M   flush=1M fail=0   reqs=649 dur=18.84s  53,072 docs/sec
+   3) add=1M   flush=1M fail=0   reqs=649 dur=19.13s  52,249 docs/sec
+   4) add=1M   flush=1M fail=0   reqs=649 dur=19.26s  51,912 docs/sec
+   5) add=1M   flush=1M fail=0   reqs=649 dur=18.98s  52,662 docs/sec
+   6) add=1M   flush=1M fail=0   reqs=649 dur=19.21s  52,056 docs/sec
+   7) add=1M   flush=1M fail=0   reqs=649 dur=18.91s  52,865 docs/sec
+   8) add=1M   flush=1M fail=0   reqs=649 dur=19.25s  51,934 docs/sec
+   9) add=1M   flush=1M fail=0   reqs=649 dur=19.44s  51,440 docs/sec
+  10) add=1M   flush=1M fail=0   reqs=649 dur=19.24s  51,966 docs/sec
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+docs/sec: min [50,165] max [53,072] mean [52,011]
+```
+
+## Mock Server
+
+The `--mockserver` flag allows to run the benchmark against a "mock server", in this case Nginx, to understand a theoretical performance of the client, without the overhead of a real Elasticsearch cluster.
+
+```
+ELASTICSEARCH_URL=http://server:8000 go run benchmarks.go --dataset=small --count=1_000_000 --flush=2MB --warmup=0 --mockserver
+small: run [10x] warmup [0x] shards [3] replicas [0] workers [8] flush [2.0 MB] wait [1s]
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+   1) add=1M   flush=0  fail=0   reqs=56  dur=810ms   1,222,493 docs/sec
+   2) add=1M   flush=0  fail=0   reqs=56  dur=810ms   1,230,012 docs/sec
+   3) add=1M   flush=0  fail=0   reqs=56  dur=790ms   1,251,564 docs/sec
+   4) add=1M   flush=0  fail=0   reqs=56  dur=840ms   1,187,648 docs/sec
+   5) add=1M   flush=0  fail=0   reqs=56  dur=800ms   1,237,623 docs/sec
+   6) add=1M   flush=0  fail=0   reqs=56  dur=800ms   1,237,623 docs/sec
+   7) add=1M   flush=0  fail=0   reqs=56  dur=800ms   1,240,694 docs/sec
+   8) add=1M   flush=0  fail=0   reqs=56  dur=820ms   1,216,545 docs/sec
+   9) add=1M   flush=0  fail=0   reqs=56  dur=790ms   1,253,132 docs/sec
+  10) add=1M   flush=0  fail=0   reqs=56  dur=810ms   1,223,990 docs/sec
+▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
+docs/sec: min [1,187,648] max [1,253,132] mean [1,233,818]
+```
+
+## Environment
+
+Please note that these results are only illustrative, and the real performance depends on many factors:
+the size and structure of your data, the index settings and mappings, the cluster setup or the hardware specification.
+
+The benchmarks have been run in the following environment:
+
+* OS: Ubuntu 18.04.4 LTS (5.0.0-1031-gcp)
+* Client: A `n2-standard-8` [GCP instance](https://cloud.google.com/compute/docs/machine-types#n2_machine_types) (8 vCPUs/32GB RAM)
+* Server: A `n2-standard-16` [GCP instance](https://cloud.google.com/compute/docs/machine-types#n2_machine_types) (16 vCPUs/64GB RAM)
+* Disk: A [local SSD](https://cloud.google.com/compute/docs/disks#localssds) formatted as `ext4` on NVMe interface for Elasticsearch data
+* A single-node Elasticsearch cluster, `7.6.0`, [default distribution](https://www.elastic.co/downloads/elasticsearch), installed from a TAR, with 4GB locked for heap
+* Nginx 1.17.8 with [`nginx.conf`](etc/nginx.conf)
diff --git a/_examples/bulk/benchmarks/benchmarks.go b/_examples/bulk/benchmarks/benchmarks.go
new file mode 100644
index 0000000000..96c2093ec8
--- /dev/null
+++ b/_examples/bulk/benchmarks/benchmarks.go
@@ -0,0 +1,252 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+// This example demonstrates indexing documents using the esutil.BulkIndexer helper.
+//
+// You can configure the settings with command line flags:
+//
+//     go run benchmark.go --dataset=httplog --runs=15 --count=1_000_000 --shards=5 --replicas=1 --flush=1MB
+
+package main
+
+import (
+	"flag"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"runtime"
+	"strings"
+	"time"
+
+	"github.com/dustin/go-humanize"
+	"github.com/mailru/easyjson"
+	"github.com/valyala/fasthttp"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+
+	"github.com/elastic/go-elasticsearch/v7/_examples/bulk/benchmarks/model"
+	"github.com/elastic/go-elasticsearch/v7/_examples/bulk/benchmarks/runner"
+)
+
+type humanBytes uint64
+
+func (b *humanBytes) String() string { return humanize.Bytes(uint64(*b)) }
+func (b *humanBytes) Set(v string) error {
+	n, err := humanize.ParseBytes(v)
+	*b = humanBytes(n)
+	return err
+}
+
+var (
+	indexName     string
+	datasetName   string
+	numWorkers    int
+	flushBytes    humanBytes
+	numRuns       int
+	numWarmupRuns int
+	numItems      int
+	numShards     int
+	numReplicas   int
+	wait          time.Duration
+	useFasthttp   bool
+	useEasyjson   bool
+	mockserver    bool
+	debug         bool
+)
+
+func init() {
+	flag.StringVar(&indexName, "index", "test-bulk-benchmarks", "Index name")
+	flag.StringVar(&datasetName, "dataset", "small", "Dataset to use for indexing")
+	flag.IntVar(&numWorkers, "workers", runtime.NumCPU(), "Number of indexer workers")
+	flag.Var(&flushBytes, "flush", "Flush threshold in bytes (default 3MB)")
+	flag.IntVar(&numRuns, "runs", 10, "Number of runs")
+	flag.IntVar(&numWarmupRuns, "warmup", 3, "Number of warmup runs")
+	flag.IntVar(&numItems, "count", 100000, "Number of documents to generate")
+	flag.IntVar(&numShards, "shards", 3, "Number of index shards")
+	flag.IntVar(&numReplicas, "replicas", 0, "Number of index replicas (default 0)")
+	flag.DurationVar(&wait, "wait", time.Second, "Wait duration between runs")
+	flag.BoolVar(&useFasthttp, "fasthttp", false, "Use valyala/fasthttp for HTTP transport")
+	flag.BoolVar(&useEasyjson, "easyjson", false, "Use mailru/easyjson for JSON decoding")
+	flag.BoolVar(&mockserver, "mockserver", false, "Measure added, not flushed items")
+	flag.BoolVar(&debug, "debug", false, "Enable logging output")
+	flag.Parse()
+}
+
+func main() {
+	log.SetFlags(0)
+
+	indexName = indexName + "-" + datasetName
+	if flushBytes < 1 {
+		flushBytes = humanBytes(3e+6)
+	}
+
+	clientCfg := elasticsearch.Config{}
+
+	if useFasthttp {
+		clientCfg.Transport = &fasthttpTransport{}
+	}
+
+	if debug {
+		clientCfg.Logger = &estransport.ColorLogger{Output: os.Stdout, EnableRequestBody: true, EnableResponseBody: true}
+	}
+
+	es, _ := elasticsearch.NewClient(clientCfg)
+
+	runnerCfg := runner.Config{
+		Client: es,
+
+		IndexName:     indexName,
+		DatasetName:   datasetName,
+		NumShards:     numShards,
+		NumReplicas:   numReplicas,
+		NumItems:      numItems,
+		NumRuns:       numRuns,
+		NumWarmupRuns: numWarmupRuns,
+		NumWorkers:    numWorkers,
+		FlushBytes:    int(flushBytes),
+		Wait:          wait,
+		Mockserver:    mockserver,
+	}
+
+	if useEasyjson {
+		runnerCfg.Decoder = easyjsonDecoder{}
+	}
+
+	runner, err := runner.NewRunner(runnerCfg)
+	if err != nil {
+		log.Fatalf("Error creating runner: %s", err)
+	}
+
+	done := make(chan os.Signal)
+	signal.Notify(done, os.Interrupt)
+
+	go func() { <-done; log.Println("\r" + strings.Repeat("▁", 110)); runner.Report(); os.Exit(0) }()
+	defer func() { log.Println(strings.Repeat("▁", 110)); runner.Report() }()
+
+	log.Printf(
+		"%s: run [%sx] warmup [%dx] shards [%d] replicas [%d] workers [%d] flush [%s] wait [%s]%s%s",
+		datasetName,
+		humanize.Comma(int64(numRuns)),
+		numWarmupRuns,
+		numShards,
+		numReplicas,
+		numWorkers,
+		humanize.Bytes(uint64(flushBytes)),
+		wait,
+		func() string {
+			if useFasthttp {
+				return " fasthttp"
+			}
+			return ""
+		}(),
+		func() string {
+			if useEasyjson {
+				return " easyjson"
+			}
+			return ""
+		}())
+	log.Println(strings.Repeat("▔", 110))
+
+	runner.Run()
+}
+
+// easyjsonDecoder implements a JSON decoder for the indexer
+// via the "github.com/mailru/easyjson" package.
+// See _examples/encoding for a demo.
+
+type easyjsonDecoder struct{}
+
+func (d easyjsonDecoder) UnmarshalFromReader(r io.Reader, blk *esutil.BulkIndexerResponse) error {
+	var v model.BulkIndexerResponse
+	if err := easyjson.UnmarshalFromReader(r, &v); err != nil {
+		return err
+	}
+	blk.Took = v.Took
+	blk.HasErrors = v.HasErrors
+	blk.Items = v.Items
+
+	return nil
+}
+
+// fasthttpTransport implements HTTP transport for the Elasticsearch client
+// via the "github.com/valyala/fasthttp" package.
+// See _examples/fasthttp for a demo.
+
+type fasthttpTransport struct{}
+
+func (t *fasthttpTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	freq := fasthttp.AcquireRequest()
+	defer fasthttp.ReleaseRequest(freq)
+
+	fres := fasthttp.AcquireResponse()
+	defer fasthttp.ReleaseResponse(fres)
+
+	t.copyRequest(freq, req)
+
+	err := fasthttp.Do(freq, fres)
+	if err != nil {
+		return nil, err
+	}
+
+	res := &http.Response{Header: make(http.Header)}
+	t.copyResponse(res, fres)
+
+	return res, nil
+}
+
+func (t *fasthttpTransport) copyRequest(dst *fasthttp.Request, src *http.Request) *fasthttp.Request {
+	if src.Method == "GET" && src.Body != nil {
+		src.Method = "POST"
+	}
+
+	dst.SetHost(src.Host)
+	dst.SetRequestURI(src.URL.String())
+
+	dst.Header.SetRequestURI(src.URL.String())
+	dst.Header.SetMethod(src.Method)
+
+	for k, vv := range src.Header {
+		for _, v := range vv {
+			dst.Header.Set(k, v)
+		}
+	}
+
+	if src.Body != nil {
+		dst.SetBodyStream(src.Body, -1)
+	}
+
+	return dst
+}
+
+func (t *fasthttpTransport) copyResponse(dst *http.Response, src *fasthttp.Response) *http.Response {
+	dst.StatusCode = src.StatusCode()
+
+	src.Header.VisitAll(func(k, v []byte) {
+		dst.Header.Set(string(k), string(v))
+	})
+
+	dst.Body = ioutil.NopCloser(strings.NewReader(string(src.Body())))
+
+	return dst
+}
diff --git a/_examples/bulk/benchmarks/data/httplog/document.json b/_examples/bulk/benchmarks/data/httplog/document.json
new file mode 100644
index 0000000000..3032bbc681
--- /dev/null
+++ b/_examples/bulk/benchmarks/data/httplog/document.json
@@ -0,0 +1,115 @@
+{
+  "container": {
+    "image": {
+      "name": "nginx:alpine"
+    },
+    "name": "demo_nginx_1",
+    "id": "containers"
+  },
+  "agent": {
+    "hostname": "ac2f80ca6f2c",
+    "id": "e7db09cf-efab-4669-b7d1-bc61af5e2dc9",
+    "type": "filebeat",
+    "ephemeral_id": "3bcf621a-b3be-4c33-bf05-e8e5fb9b07af",
+    "version": "7.5.1"
+  },
+  "log": {
+    "file": {
+      "path": "/hostfs/var/lib/docker/containers/dfadbc398fd75cd055a3d9e2ca9b30463c996e56751c962fb17c55c6ceec754c/dfadbc398fd75cd055a3d9e2ca9b30463c996e56751c962fb17c55c6ceec754c-json.log"
+    },
+    "offset": 8095
+  },
+  "source": {
+    "address": "172.23.0.1",
+    "ip": "172.23.0.1"
+  },
+  "docker": {
+    "container": {
+      "labels": {
+        "com_docker_compose_config-hash": "725e1f526ff27e977aec78f5451b9914a91ea1d6764d9387030e270ad9ac5866",
+        "com_docker_compose_oneoff": "False",
+        "com_docker_compose_project": "demo",
+        "com_docker_compose_project_config_files": "docker-compose.yml",
+        "com_docker_compose_service": "nginx",
+        "com_docker_compose_container-number": "1",
+        "com_docker_compose_version": "1.25.4",
+        "com_docker_compose_project_working_dir": "/.../elastic-stack-demo",
+        "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
+      }
+    }
+  },
+  "ecs": {
+    "version": "1.1.0"
+  },
+  "stream": "stdout",
+  "host": {
+    "hostname": "ac2f80ca6f2c",
+    "os": {
+      "kernel": "4.19.76-linuxkit",
+      "codename": "Core",
+      "name": "CentOS Linux",
+      "family": "redhat",
+      "version": "7 (Core)",
+      "platform": "centos"
+    },
+    "containerized": true,
+    "name": "ac2f80ca6f2c",
+    "architecture": "x86_64"
+  },
+  "event": {
+    "timezone": "+00:00",
+    "created": "2020-02-20T08:59:42.312Z",
+    "module": "nginx",
+    "dataset": "nginx.access"
+  },
+  "user_agent": {
+    "original": "curl/7.64.0",
+    "name": "curl",
+    "device": {
+      "name": "Other"
+    },
+    "version": "7.64.0"
+  },
+  "nginx": {
+    "access": {
+      "remote_ip_list": [
+        "172.23.0.1"
+      ]
+    }
+  },
+  "fileset": {
+    "name": "access"
+  },
+  "url": {
+    "original": "/"
+  },
+  "tags": [
+    "service-A"
+  ],
+  "input": {
+    "type": "container"
+  },
+  "@timestamp": "2020-02-20T08:59:42.000Z",
+  "service": {
+    "type": "nginx"
+  },
+  "http": {
+    "request": {
+      "referrer": "-",
+      "method": "GET"
+    },
+    "response": {
+      "status_code": 200,
+      "body": {
+        "bytes": 43
+      }
+    },
+    "version": "1.1"
+  },
+  "fields": {
+    "environment": "staging"
+  },
+  "user": {
+    "name": "-"
+  }
+}
diff --git a/_examples/bulk/benchmarks/data/httplog/mapping.json b/_examples/bulk/benchmarks/data/httplog/mapping.json
new file mode 100644
index 0000000000..f85118fbe4
--- /dev/null
+++ b/_examples/bulk/benchmarks/data/httplog/mapping.json
@@ -0,0 +1,1275 @@
+{
+  "mappings": {
+    "_meta": {
+      "version": "8-SNAPSHOT"
+    },
+
+    "dynamic_templates": [
+      {
+        "labels": {
+          "path_match": "labels.*",
+          "match_mapping_type": "string",
+          "mapping": {
+            "type": "keyword"
+          }
+        }
+      },
+      {
+        "container.labels": {
+          "path_match": "container.labels.*",
+          "match_mapping_type": "string",
+          "mapping": {
+            "type": "keyword"
+          }
+        }
+      },
+      {
+        "fields": {
+          "path_match": "fields.*",
+          "match_mapping_type": "string",
+          "mapping": {
+            "type": "keyword"
+          }
+        }
+      },
+      {
+        "docker.container.labels": {
+          "path_match": "docker.container.labels.*",
+          "match_mapping_type": "string",
+          "mapping": {
+            "type": "keyword"
+          }
+        }
+      },
+      {
+        "docker.attrs": {
+          "path_match": "docker.attrs.*",
+          "match_mapping_type": "string",
+          "mapping": {
+            "type": "keyword"
+          }
+        }
+      },
+      {
+        "strings_as_keyword": {
+          "match_mapping_type": "string",
+          "mapping": {
+            "ignore_above": 1024,
+            "type": "keyword"
+          }
+        }
+      }
+    ],
+
+    "date_detection": false,
+
+    "properties": {
+      "@timestamp": {
+        "type": "date"
+      },
+      "agent": {
+        "properties": {
+          "ephemeral_id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "hostname": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "type": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "version": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "container": {
+        "properties": {
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "image": {
+            "properties": {
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "tag": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "labels": {
+            "type": "object"
+          },
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "runtime": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "docker": {
+        "properties": {
+          "attrs": {
+            "type": "object"
+          },
+          "container": {
+            "properties": {
+              "labels": {
+                "properties": {
+                  "com_docker_compose_config-hash": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_container-number": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_oneoff": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_project": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_project_config_files": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_project_working_dir": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_service": {
+                    "type": "keyword"
+                  },
+                  "com_docker_compose_version": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_build-date": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_license": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_name": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_schema-version": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_url": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_usage": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_vcs-ref": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_vcs-url": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_vendor": {
+                    "type": "keyword"
+                  },
+                  "org_label-schema_version": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_created": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_documentation": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_licenses": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_revision": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_source": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_title": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_url": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_vendor": {
+                    "type": "keyword"
+                  },
+                  "org_opencontainers_image_version": {
+                    "type": "keyword"
+                  }
+                }
+              }
+            }
+          }
+        }
+      },
+      "ecs": {
+        "properties": {
+          "version": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "error": {
+        "properties": {
+          "code": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "message": {
+            "type": "text",
+            "norms": false
+          },
+          "stack_trace": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "type": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "event": {
+        "properties": {
+          "action": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "category": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "code": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "created": {
+            "type": "date"
+          },
+          "dataset": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "duration": {
+            "type": "long"
+          },
+          "end": {
+            "type": "date"
+          },
+          "hash": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "ingested": {
+            "type": "date"
+          },
+          "kind": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "module": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "original": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "outcome": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "provider": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "risk_score": {
+            "type": "float"
+          },
+          "risk_score_norm": {
+            "type": "float"
+          },
+          "sequence": {
+            "type": "long"
+          },
+          "severity": {
+            "type": "long"
+          },
+          "start": {
+            "type": "date"
+          },
+          "timezone": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "type": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "fields": {
+        "properties": {
+          "environment": {
+            "type": "keyword"
+          }
+        }
+      },
+      "fileset": {
+        "properties": {
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "geo": {
+        "properties": {
+          "city_name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "continent_name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "country_iso_code": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "country_name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "location": {
+            "type": "geo_point"
+          },
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "region_iso_code": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "region_name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "host": {
+        "properties": {
+          "architecture": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "containerized": {
+            "type": "boolean"
+          },
+          "domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "geo": {
+            "properties": {
+              "city_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "continent_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "country_iso_code": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "country_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "location": {
+                "type": "geo_point"
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "region_iso_code": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "region_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "hostname": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "ip": {
+            "type": "ip"
+          },
+          "mac": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "os": {
+            "properties": {
+              "build": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "codename": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "family": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "full": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "kernel": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "platform": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "version": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "type": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "uptime": {
+            "type": "long"
+          },
+          "user": {
+            "properties": {
+              "domain": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "email": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "full_name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "group": {
+                "properties": {
+                  "domain": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "hash": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              }
+            }
+          }
+        }
+      },
+      "http": {
+        "properties": {
+          "request": {
+            "properties": {
+              "body": {
+                "properties": {
+                  "bytes": {
+                    "type": "long"
+                  },
+                  "content": {
+                    "type": "keyword",
+                    "fields": {
+                      "text": {
+                        "type": "text",
+                        "norms": false
+                      }
+                    },
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "bytes": {
+                "type": "long"
+              },
+              "method": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "referrer": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "response": {
+            "properties": {
+              "body": {
+                "properties": {
+                  "bytes": {
+                    "type": "long"
+                  },
+                  "content": {
+                    "type": "keyword",
+                    "fields": {
+                      "text": {
+                        "type": "text",
+                        "norms": false
+                      }
+                    },
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "bytes": {
+                "type": "long"
+              },
+              "status_code": {
+                "type": "long"
+              }
+            }
+          },
+          "version": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "input": {
+        "properties": {
+          "type": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "labels": {
+        "type": "object"
+      },
+      "log": {
+        "properties": {
+          "file": {
+            "properties": {
+              "path": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "flags": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "level": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "logger": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "offset": {
+            "type": "long"
+          },
+          "origin": {
+            "properties": {
+              "file": {
+                "properties": {
+                  "line": {
+                    "type": "long"
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "function": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "original": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "source": {
+            "properties": {
+              "address": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "syslog": {
+            "properties": {
+              "facility": {
+                "properties": {
+                  "code": {
+                    "type": "long"
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "priority": {
+                "type": "long"
+              },
+              "severity": {
+                "properties": {
+                  "code": {
+                    "type": "long"
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              }
+            }
+          }
+        }
+      },
+      "message": {
+        "type": "text",
+        "norms": false
+      },
+      "nginx": {
+        "properties": {
+          "access": {
+            "properties": {
+              "geoip": {
+                "type": "object"
+              },
+              "user_agent": {
+                "type": "object"
+              }
+            }
+          },
+          "error": {
+            "properties": {
+              "connection_id": {
+                "type": "long"
+              }
+            }
+          }
+        }
+      },
+      "object_key": {
+        "type": "keyword",
+        "ignore_above": 1024
+      },
+      "source": {
+        "properties": {
+          "address": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "as": {
+            "properties": {
+              "number": {
+                "type": "long"
+              },
+              "organization": {
+                "properties": {
+                  "name": {
+                    "type": "keyword",
+                    "fields": {
+                      "text": {
+                        "type": "text",
+                        "norms": false
+                      }
+                    },
+                    "ignore_above": 1024
+                  }
+                }
+              }
+            }
+          },
+          "bytes": {
+            "type": "long"
+          },
+          "domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "geo": {
+            "properties": {
+              "city_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "continent_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "country_iso_code": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "country_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "location": {
+                "type": "geo_point"
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "region_iso_code": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "region_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "ip": {
+            "type": "ip"
+          },
+          "mac": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "nat": {
+            "properties": {
+              "ip": {
+                "type": "ip"
+              },
+              "port": {
+                "type": "long"
+              }
+            }
+          },
+          "packets": {
+            "type": "long"
+          },
+          "port": {
+            "type": "long"
+          },
+          "registered_domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "service": {
+            "properties": {
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "top_level_domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "user": {
+            "properties": {
+              "domain": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "email": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "full_name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "group": {
+                "properties": {
+                  "domain": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "hash": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              }
+            }
+          }
+        }
+      },
+      "stream": {
+        "type": "keyword",
+        "ignore_above": 1024
+      },
+      "tags": {
+        "type": "keyword",
+        "ignore_above": 1024
+      },
+      "timeseries": {
+        "properties": {
+          "instance": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "url": {
+        "properties": {
+          "domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "extension": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "fragment": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "full": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "original": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "password": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "path": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "port": {
+            "type": "long"
+          },
+          "query": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "registered_domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "scheme": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "top_level_domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "username": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "user": {
+        "properties": {
+          "audit": {
+            "properties": {
+              "group": {
+                "properties": {
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "domain": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "effective": {
+            "properties": {
+              "group": {
+                "properties": {
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "email": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "filesystem": {
+            "properties": {
+              "group": {
+                "properties": {
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "full_name": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "group": {
+            "properties": {
+              "domain": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "hash": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "id": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "name": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "owner": {
+            "properties": {
+              "group": {
+                "properties": {
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "saved": {
+            "properties": {
+              "group": {
+                "properties": {
+                  "id": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  },
+                  "name": {
+                    "type": "keyword",
+                    "ignore_above": 1024
+                  }
+                }
+              },
+              "id": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "terminal": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      },
+      "user_agent": {
+        "properties": {
+          "device": {
+            "properties": {
+              "name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "name": {
+            "type": "keyword",
+            "ignore_above": 1024
+          },
+          "original": {
+            "type": "keyword",
+            "fields": {
+              "text": {
+                "type": "text",
+                "norms": false
+              }
+            },
+            "ignore_above": 1024
+          },
+          "os": {
+            "properties": {
+              "family": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "full": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "full_name": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "kernel": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "name": {
+                "type": "keyword",
+                "fields": {
+                  "text": {
+                    "type": "text",
+                    "norms": false
+                  }
+                },
+                "ignore_above": 1024
+              },
+              "platform": {
+                "type": "keyword",
+                "ignore_above": 1024
+              },
+              "version": {
+                "type": "keyword",
+                "ignore_above": 1024
+              }
+            }
+          },
+          "version": {
+            "type": "keyword",
+            "ignore_above": 1024
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/_examples/bulk/benchmarks/data/small/document.json b/_examples/bulk/benchmarks/data/small/document.json
new file mode 100644
index 0000000000..933b2785ca
--- /dev/null
+++ b/_examples/bulk/benchmarks/data/small/document.json
@@ -0,0 +1,10 @@
+{
+  "title": "Test",
+  "tags": [
+    "one",
+    "two",
+    "three"
+  ],
+  "count": 42,
+  "time": "2020-02-20T08:59:42.000Z"
+}
diff --git a/_examples/bulk/benchmarks/data/small/mapping.json b/_examples/bulk/benchmarks/data/small/mapping.json
new file mode 100644
index 0000000000..344b227458
--- /dev/null
+++ b/_examples/bulk/benchmarks/data/small/mapping.json
@@ -0,0 +1,15 @@
+{
+  "mappings": {
+    "_meta": {
+      "version": "8-SNAPSHOT"
+    },
+
+    "properties": {
+      "count": { "type": "long" },
+      "tags":  { "type": "keyword" },
+      "time":  { "type": "date" },
+      "title": { "type": "text" }
+      }
+    }
+  }
+}
diff --git a/_examples/bulk/benchmarks/etc/nginx.conf b/_examples/bulk/benchmarks/etc/nginx.conf
new file mode 100644
index 0000000000..92bbe19258
--- /dev/null
+++ b/_examples/bulk/benchmarks/etc/nginx.conf
@@ -0,0 +1,42 @@
+user nginx;
+
+worker_processes auto;
+worker_rlimit_nofile 10240;
+pid /tmp/nginx.pid;
+
+error_log off;
+
+events {
+  worker_connections  10240;
+  accept_mutex        off;
+  multi_accept        off;
+}
+
+http {
+  access_log off;
+  error_log  off;
+
+  keepalive_timeout  300s;
+  keepalive_requests 1000000;
+
+  default_type application/json;
+
+  gzip on;
+  gzip_comp_level 5;
+  gzip_min_length 256;
+
+  client_max_body_size 100m;
+
+  server {
+    listen 8000 default_server;
+
+    location / {
+      return 200 '{"took": 0, "errors": false, "items": []}\n';
+    }
+
+    location = /favicon.ico {
+      access_log off;
+      return 204;
+    }
+  }
+}
diff --git a/_examples/bulk/benchmarks/go.mod b/_examples/bulk/benchmarks/go.mod
new file mode 100644
index 0000000000..c71fd3ab98
--- /dev/null
+++ b/_examples/bulk/benchmarks/go.mod
@@ -0,0 +1,13 @@
+module github.com/elastic/go-elasticsearch/v7/_examples/bulk/benchmarks
+
+go 1.11
+
+replace github.com/elastic/go-elasticsearch/v7 => ../../..
+
+require (
+	github.com/dustin/go-humanize v1.0.0
+	github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210608143310-9747f0e42f35
+	github.com/mailru/easyjson v0.7.1
+	github.com/montanaflynn/stats v0.6.3
+	github.com/valyala/fasthttp v1.9.0
+)
diff --git a/_examples/bulk/benchmarks/model/model.go b/_examples/bulk/benchmarks/model/model.go
new file mode 100644
index 0000000000..9e198c3249
--- /dev/null
+++ b/_examples/bulk/benchmarks/model/model.go
@@ -0,0 +1,34 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//go:generate easyjson $GOFILE
+
+package model
+
+import (
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+// BulkIndexerResponse wraps the esutil.BulkIndexerResponse,
+// and implements the esutil.UnmarshalFromReader() method,
+// in order to demonstrate usage of a third-party JSON decoder,
+// such as "mailru/easyjson".
+//
+// easyjson:json
+type BulkIndexerResponse struct {
+	esutil.BulkIndexerResponse
+}
diff --git a/_examples/bulk/benchmarks/runner/runner.go b/_examples/bulk/benchmarks/runner/runner.go
new file mode 100644
index 0000000000..f611141d87
--- /dev/null
+++ b/_examples/bulk/benchmarks/runner/runner.go
@@ -0,0 +1,265 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package runner
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"math"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/dustin/go-humanize"
+	"github.com/montanaflynn/stats"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+// NewRunner returns new BulkIndexer benchmarking runner.
+//
+func NewRunner(cfg Config) (*Runner, error) {
+	return &Runner{config: cfg}, nil
+}
+
+// Runner represents the BulkIndexer benchmarking runner.
+//
+type Runner struct {
+	config Config
+
+	doc           []byte
+	indexSettings strings.Builder
+
+	samples    []float64
+	throughput map[string]float64
+}
+
+// Config represents configuration for Runner.
+//
+type Config struct {
+	IndexName   string
+	DatasetName string
+	Client      *elasticsearch.Client
+	Decoder     esutil.BulkResponseJSONDecoder
+
+	NumShards     int
+	NumReplicas   int
+	NumItems      int
+	NumRuns       int
+	NumWarmupRuns int
+	NumWorkers    int
+	FlushBytes    int
+	Wait          time.Duration
+	Mockserver    bool
+}
+
+// Report prints statistics from the benchmark runs.
+//
+func (r *Runner) Report() error {
+	r.throughput = map[string]float64{
+		"min": func() float64 { v, _ := stats.Min(r.samples); return v }(),
+		"max": func() float64 { v, _ := stats.Max(r.samples); return v }(),
+		"mdn": func() float64 { v, _ := stats.Median(r.samples); return v }(),
+		"p25": func() float64 { v, _ := stats.Percentile(r.samples, 25); return v }(),
+		"p50": func() float64 { v, _ := stats.Percentile(r.samples, 50); return v }(),
+		"p75": func() float64 { v, _ := stats.Percentile(r.samples, 75); return v }(),
+		"p95": func() float64 { v, _ := stats.Percentile(r.samples, 95); return v }(),
+	}
+
+	log.Printf(
+		"docs/sec: min [%s] max [%s] mean [%s]",
+		humanize.Comma(int64(r.throughput["min"])),
+		humanize.Comma(int64(r.throughput["max"])),
+		humanize.Comma(int64(r.throughput["mdn"])),
+	)
+
+	ratio := 50.0 / r.throughput["max"]
+
+	if !math.IsNaN(r.throughput["p25"]) {
+		fmt.Println("25%",
+			strings.Repeat("▆", int(r.throughput["p25"]*ratio)),
+			humanize.Comma(int64(r.throughput["p25"])), "docs/sec")
+	}
+	if !math.IsNaN(r.throughput["p50"]) {
+		fmt.Println("50%",
+			strings.Repeat("▆", int(r.throughput["p50"]*ratio)),
+			humanize.Comma(int64(r.throughput["p50"])), "docs/sec")
+	}
+	if !math.IsNaN(r.throughput["p75"]) {
+		fmt.Println("75%",
+			strings.Repeat("▆", int(r.throughput["p75"]*ratio)),
+			humanize.Comma(int64(r.throughput["p75"])), "docs/sec")
+	}
+	if !math.IsNaN(r.throughput["p95"]) {
+		fmt.Println("95%",
+			strings.Repeat("▆", int(r.throughput["p95"]*ratio)),
+			humanize.Comma(int64(r.throughput["p95"])), "docs/sec")
+	}
+
+	return nil
+}
+
+// Run executes the benchmark runs.
+//
+func (r *Runner) Run() error {
+	for n := 1; n <= r.config.NumWarmupRuns; n++ {
+		if err := r.run(n, false); err != nil {
+			log.Fatalf("Runner error: %s", err)
+		}
+	}
+
+	for n := 1; n <= r.config.NumRuns; n++ {
+		if err := r.run(n, true); err != nil {
+			log.Fatalf("Runner error: %s", err)
+		}
+	}
+
+	return nil
+}
+
+// setup re-creates the index for a benchmark run.
+//
+func (r *Runner) setup() error {
+	fm, err := os.Open(filepath.Join("data", r.config.DatasetName, "mapping.json"))
+	if err != nil {
+		return fmt.Errorf("setup: reading mapping: %s", err)
+	}
+
+	var mappingEnvelope map[string]interface{}
+	json.NewDecoder(fm).Decode(&mappingEnvelope)
+	mapping, err := json.Marshal(mappingEnvelope["mappings"])
+	if err != nil {
+		return fmt.Errorf("setup: encoding mapping: %s", err)
+	}
+
+	r.indexSettings.WriteString(`{ "settings": `)
+	fmt.Fprintf(&r.indexSettings, `{"number_of_shards": %d, "number_of_replicas": %d, "refresh_interval":"5s"}`, r.config.NumShards, r.config.NumReplicas)
+	r.indexSettings.WriteString(`, "mappings":`)
+	r.indexSettings.Write(mapping)
+	r.indexSettings.WriteString(`}`)
+
+	f, err := os.Open(filepath.Join("data", r.config.DatasetName, "document.json"))
+	if err != nil {
+		return fmt.Errorf("setup: reading document: %s", err)
+	}
+	var m map[string]interface{}
+	json.NewDecoder(f).Decode(&m)
+	doc, err := json.Marshal(m)
+	if err != nil {
+		return fmt.Errorf("setup: encoding document: %s", err)
+	}
+	r.doc = doc
+
+	r.config.Client.Indices.Delete(
+		[]string{r.config.IndexName},
+		r.config.Client.Indices.Delete.WithIgnoreUnavailable(true))
+	res, err := r.config.Client.Indices.Create(
+		r.config.IndexName,
+		r.config.Client.Indices.Create.WithBody(strings.NewReader(r.indexSettings.String())),
+		r.config.Client.Indices.Create.WithWaitForActiveShards("1"))
+	if err != nil {
+		return fmt.Errorf("setup: encoding document: %s", err)
+	}
+	res.Body.Close()
+	if res.IsError() {
+		return fmt.Errorf("setup: encoding document: %s", res.String())
+	}
+
+	return nil
+}
+
+// run executes a single benchmark run n, recording stats when measure is true.
+//
+func (r *Runner) run(n int, measure bool) error {
+	if err := r.setup(); err != nil {
+		return fmt.Errorf("run: %s", err)
+	}
+
+	bi, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+		Index:         r.config.IndexName,
+		Client:        r.config.Client,
+		Decoder:       r.config.Decoder,
+		NumWorkers:    r.config.NumWorkers,
+		FlushBytes:    r.config.FlushBytes,
+		FlushInterval: time.Hour, // Disable automatic flushing
+	})
+	if err != nil {
+		return fmt.Errorf("run: %s", err)
+	}
+
+	start := time.Now().UTC()
+	for i := 1; i <= r.config.NumItems; i++ {
+		err := bi.Add(context.Background(), esutil.BulkIndexerItem{
+			Action: "index",
+			Body:   bytes.NewReader(r.doc),
+			OnFailure: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem, err error) {
+				if err != nil {
+					log.Printf("ERROR: %s", err)
+				} else {
+					log.Printf("ERROR: %s: %s", res.Error.Type, res.Error.Reason)
+				}
+			},
+		})
+		if err != nil {
+			return fmt.Errorf("run: %s", err)
+		}
+	}
+
+	if err := bi.Close(context.Background()); err != nil {
+		return fmt.Errorf("run: %s", err)
+	}
+
+	duration := time.Since(start)
+
+	if measure {
+		biStats := bi.Stats()
+
+		var numThroughput uint64
+		if r.config.Mockserver {
+			numThroughput = biStats.NumAdded
+		} else {
+			numThroughput = biStats.NumFlushed
+		}
+		sample := 1000.0 / float64(duration/time.Millisecond) * float64(numThroughput)
+		r.samples = append(r.samples, sample)
+
+		log.Printf("%4d) add=%s\tflush=%s\tfail=%s\treqs=%s\tdur=%-6s\t%6s docs/sec\n",
+			n,
+			formatInt(int(biStats.NumAdded)),
+			formatInt(int(biStats.NumFlushed)),
+			formatInt(int(biStats.NumFailed)),
+			formatInt(int(biStats.NumRequests)),
+			duration.Truncate(10*time.Millisecond),
+			humanize.Comma(int64(sample)))
+
+		time.Sleep(r.config.Wait)
+	}
+
+	return nil
+}
+
+// formatInt returns a number like 123456 as a string like 123.45K
+//
+func formatInt(i int) string {
+	return strings.ReplaceAll(strings.ToUpper(humanize.SIWithDigits(float64(i), 2, "")), " ", "")
+}
diff --git a/_examples/bulk/bulk.go b/_examples/bulk/default.go
similarity index 76%
rename from _examples/bulk/bulk.go
rename to _examples/bulk/default.go
index ebeca1fc25..cd12fe8668 100644
--- a/_examples/bulk/bulk.go
+++ b/_examples/bulk/default.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 // This example demonstrates indexing documents using the Elasticsearch "Bulk" API
@@ -5,7 +22,7 @@
 //
 // You can configure the number of documents and the batch size with command line flags:
 //
-//     go run bulk.go -count=10000 -batch=2500
+//     go run default.go -count=10000 -batch=2500
 //
 // The example intentionally doesn't use any abstractions or helper functions, to
 // demonstrate the low-level mechanics of working with the Bulk API: preparing
@@ -26,8 +43,10 @@ import (
 	"strings"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/dustin/go-humanize"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 type Article struct {
@@ -96,6 +115,11 @@ func main() {
 		currBatch  int
 	)
 
+	log.Printf(
+		"\x1b[1mBulk\x1b[0m: documents [%s] batch size [%s]",
+		humanize.Comma(int64(count)), humanize.Comma(int64(batch)))
+	log.Println(strings.Repeat("▁", 65))
+
 	// Create the Elasticsearch client
 	//
 	es, err := elasticsearch.NewDefaultClient()
@@ -118,7 +142,8 @@ func main() {
 			},
 		})
 	}
-	log.Printf("> Generated %d articles", len(articles))
+	log.Printf("→ Generated %s articles", humanize.Comma(int64(len(articles))))
+	fmt.Print("→ Sending batch ")
 
 	// Re-create the index
 	//
@@ -183,7 +208,7 @@ func main() {
 		// When a threshold is reached, execute the Bulk() request with body from buffer
 		//
 		if i > 0 && i%batch == 0 || i == count-1 {
-			log.Printf("> Batch %-2d of %d", currBatch, numBatches)
+			fmt.Printf("[%d/%d] ", currBatch, numBatches)
 
 			res, err = es.Bulk(bytes.NewReader(buf.Bytes()), es.Bulk.WithIndex(indexName))
 			if err != nil {
@@ -232,6 +257,11 @@ func main() {
 					}
 				}
 			}
+
+			// Close the response body, to prevent reaching the limit for goroutines or file handles
+			//
+			res.Body.Close()
+
 			// Reset the buffer and items counter
 			//
 			buf.Reset()
@@ -241,24 +271,25 @@ func main() {
 
 	// Report the results: number of indexed docs, number of errors, duration, indexing rate
 	//
-	log.Println(strings.Repeat("=", 80))
+	fmt.Print("\n")
+	log.Println(strings.Repeat("▔", 65))
 
 	dur := time.Since(start)
 
 	if numErrors > 0 {
 		log.Fatalf(
-			"Indexed [%d] documents with [%d] errors in %s (%.0f docs/sec)",
-			numIndexed,
-			numErrors,
+			"Indexed [%s] documents with [%s] errors in %s (%s docs/sec)",
+			humanize.Comma(int64(numIndexed)),
+			humanize.Comma(int64(numErrors)),
 			dur.Truncate(time.Millisecond),
-			1000.0/float64(dur/time.Millisecond)*float64(numIndexed),
+			humanize.Comma(int64(1000.0/float64(dur/time.Millisecond)*float64(numIndexed))),
 		)
 	} else {
 		log.Printf(
-			"Sucessfuly indexed [%d] documents in %s (%.0f docs/sec)",
-			numIndexed,
+			"Sucessfuly indexed [%s] documents in %s (%s docs/sec)",
+			humanize.Comma(int64(numIndexed)),
 			dur.Truncate(time.Millisecond),
-			1000.0/float64(dur/time.Millisecond)*float64(numIndexed),
+			humanize.Comma(int64(1000.0/float64(dur/time.Millisecond)*float64(numIndexed))),
 		)
 	}
 }
diff --git a/_examples/bulk/go.mod b/_examples/bulk/go.mod
new file mode 100644
index 0000000000..040b398042
--- /dev/null
+++ b/_examples/bulk/go.mod
@@ -0,0 +1,12 @@
+module github.com/elastic/go-elasticsearch/v7/_examples/bulk
+
+go 1.11
+
+replace github.com/elastic/go-elasticsearch/v7 => ../..
+
+require (
+	github.com/cenkalti/backoff/v4 v4.0.0
+	github.com/dustin/go-humanize v1.0.0
+	github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210608143310-9747f0e42f35
+	github.com/mailru/easyjson v0.7.7 // indirect
+)
diff --git a/_examples/bulk/indexer.go b/_examples/bulk/indexer.go
new file mode 100644
index 0000000000..0f790d7b1c
--- /dev/null
+++ b/_examples/bulk/indexer.go
@@ -0,0 +1,264 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+// This example demonstrates indexing documents using the esutil.BulkIndexer helper.
+//
+// You can configure the settings with command line flags:
+//
+//     go run indexer.go --workers=8 --count=100000 --flush=1000000
+//
+package main
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"flag"
+	"log"
+	"math/rand"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync/atomic"
+	"time"
+
+	"github.com/cenkalti/backoff/v4"
+	"github.com/dustin/go-humanize"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+type Article struct {
+	ID        int       `json:"id"`
+	Title     string    `json:"title"`
+	Body      string    `json:"body"`
+	Published time.Time `json:"published"`
+	Author    Author    `json:"author"`
+}
+
+type Author struct {
+	FirstName string `json:"first_name"`
+	LastName  string `json:"last_name"`
+}
+
+var (
+	indexName  string
+	numWorkers int
+	flushBytes int
+	numItems   int
+)
+
+func init() {
+	flag.StringVar(&indexName, "index", "test-bulk-example", "Index name")
+	flag.IntVar(&numWorkers, "workers", runtime.NumCPU(), "Number of indexer workers")
+	flag.IntVar(&flushBytes, "flush", 5e+6, "Flush threshold in bytes")
+	flag.IntVar(&numItems, "count", 10000, "Number of documents to generate")
+	flag.Parse()
+
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	log.SetFlags(0)
+
+	var (
+		articles        []*Article
+		countSuccessful uint64
+
+		res *esapi.Response
+		err error
+	)
+
+	log.Printf(
+		"\x1b[1mBulkIndexer\x1b[0m: documents [%s] workers [%d] flush [%s]",
+		humanize.Comma(int64(numItems)), numWorkers, humanize.Bytes(uint64(flushBytes)))
+	log.Println(strings.Repeat("▁", 65))
+
+	// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+	//
+	// Use a third-party package for implementing the backoff function
+	//
+	retryBackoff := backoff.NewExponentialBackOff()
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+	//
+	// Create the Elasticsearch client
+	//
+	// NOTE: For optimal performance, consider using a third-party HTTP transport package.
+	//       See an example in the "benchmarks" folder.
+	//
+	es, err := elasticsearch.NewClient(elasticsearch.Config{
+		// Retry on 429 TooManyRequests statuses
+		//
+		RetryOnStatus: []int{502, 503, 504, 429},
+
+		// Configure the backoff function
+		//
+		RetryBackoff: func(i int) time.Duration {
+			if i == 1 {
+				retryBackoff.Reset()
+			}
+			return retryBackoff.NextBackOff()
+		},
+
+		// Retry up to 5 attempts
+		//
+		MaxRetries: 5,
+	})
+	if err != nil {
+		log.Fatalf("Error creating the client: %s", err)
+	}
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+	//
+	// Create the BulkIndexer
+	//
+	// NOTE: For optimal performance, consider using a third-party JSON decoding package.
+	//       See an example in the "benchmarks" folder.
+	//
+	bi, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+		Index:         indexName,        // The default index name
+		Client:        es,               // The Elasticsearch client
+		NumWorkers:    numWorkers,       // The number of worker goroutines
+		FlushBytes:    int(flushBytes),  // The flush threshold in bytes
+		FlushInterval: 30 * time.Second, // The periodic flush interval
+	})
+	if err != nil {
+		log.Fatalf("Error creating the indexer: %s", err)
+	}
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	// Generate the articles collection
+	//
+	names := []string{"Alice", "John", "Mary"}
+	for i := 1; i <= numItems; i++ {
+		articles = append(articles, &Article{
+			ID:        i,
+			Title:     strings.Join([]string{"Title", strconv.Itoa(i)}, " "),
+			Body:      "Lorem ipsum dolor sit amet...",
+			Published: time.Now().Round(time.Second).UTC().AddDate(0, 0, i),
+			Author: Author{
+				FirstName: names[rand.Intn(len(names))],
+				LastName:  "Smith",
+			},
+		})
+	}
+	log.Printf("→ Generated %s articles", humanize.Comma(int64(len(articles))))
+
+	// Re-create the index
+	//
+	if res, err = es.Indices.Delete([]string{indexName}, es.Indices.Delete.WithIgnoreUnavailable(true)); err != nil || res.IsError() {
+		log.Fatalf("Cannot delete index: %s", err)
+	}
+	res.Body.Close()
+	res, err = es.Indices.Create(indexName)
+	if err != nil {
+		log.Fatalf("Cannot create index: %s", err)
+	}
+	if res.IsError() {
+		log.Fatalf("Cannot create index: %s", res)
+	}
+	res.Body.Close()
+
+	start := time.Now().UTC()
+
+	// Loop over the collection
+	//
+	for _, a := range articles {
+		// Prepare the data payload: encode article to JSON
+		//
+		data, err := json.Marshal(a)
+		if err != nil {
+			log.Fatalf("Cannot encode article %d: %s", a.ID, err)
+		}
+
+		// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+		//
+		// Add an item to the BulkIndexer
+		//
+		err = bi.Add(
+			context.Background(),
+			esutil.BulkIndexerItem{
+				// Action field configures the operation to perform (index, create, delete, update)
+				Action: "index",
+
+				// DocumentID is the (optional) document ID
+				DocumentID: strconv.Itoa(a.ID),
+
+				// Body is an `io.Reader` with the payload
+				Body: bytes.NewReader(data),
+
+				// OnSuccess is called for each successful operation
+				OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
+					atomic.AddUint64(&countSuccessful, 1)
+				},
+
+				// OnFailure is called for each failed operation
+				OnFailure: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem, err error) {
+					if err != nil {
+						log.Printf("ERROR: %s", err)
+					} else {
+						log.Printf("ERROR: %s: %s", res.Error.Type, res.Error.Reason)
+					}
+				},
+			},
+		)
+		if err != nil {
+			log.Fatalf("Unexpected error: %s", err)
+		}
+		// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+	}
+
+	// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+	// Close the indexer
+	//
+	if err := bi.Close(context.Background()); err != nil {
+		log.Fatalf("Unexpected error: %s", err)
+	}
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	biStats := bi.Stats()
+
+	// Report the results: number of indexed docs, number of errors, duration, indexing rate
+	//
+	log.Println(strings.Repeat("▔", 65))
+
+	dur := time.Since(start)
+
+	if biStats.NumFailed > 0 {
+		log.Fatalf(
+			"Indexed [%s] documents with [%s] errors in %s (%s docs/sec)",
+			humanize.Comma(int64(biStats.NumFlushed)),
+			humanize.Comma(int64(biStats.NumFailed)),
+			dur.Truncate(time.Millisecond),
+			humanize.Comma(int64(1000.0/float64(dur/time.Millisecond)*float64(biStats.NumFlushed))),
+		)
+	} else {
+		log.Printf(
+			"Sucessfuly indexed [%s] documents in %s (%s docs/sec)",
+			humanize.Comma(int64(biStats.NumFlushed)),
+			dur.Truncate(time.Millisecond),
+			humanize.Comma(int64(1000.0/float64(dur/time.Millisecond)*float64(biStats.NumFlushed))),
+		)
+	}
+}
diff --git a/_examples/bulk/kafka/.env b/_examples/bulk/kafka/.env
new file mode 100644
index 0000000000..2169e14570
--- /dev/null
+++ b/_examples/bulk/kafka/.env
@@ -0,0 +1,7 @@
+COMPOSE_PROJECT_NAME=kafka
+
+CONFLUENT_VERSION=5.4.0
+ELASTIC_VERSION=8.0.0-SNAPSHOT
+
+KAFKA_MEMORY=1G
+ES_MEMORY=1G
diff --git a/_examples/bulk/kafka/Makefile b/_examples/bulk/kafka/Makefile
new file mode 100644
index 0000000000..64ce79bfe0
--- /dev/null
+++ b/_examples/bulk/kafka/Makefile
@@ -0,0 +1,49 @@
+SHELL := /bin/bash
+
+test:
+	go build -o /dev/null kafka.go
+
+setup: stack status wait_for_kibana load_kibana_dashboard
+
+clean:
+	@docker-compose down --volumes
+
+run:
+	go run kafka.go
+
+stack:
+	@docker-compose up --detach
+
+status:
+	@{ \
+		cols=`tput cols`; max=98; i=1; \
+		while [[ "$$i" -lt "$$cols" && "$$i" -lt "$$max" ]]; do printf '-'; let i=$$i+1; done; printf "\n"; \
+		docker-compose ps; \
+		i=1; while [[ "$$i" -lt "$$cols" && "$$i" -lt "$$max" ]]; do printf '-'; let i=$$i+1; done; printf "\n"; \
+	}
+
+wait_for_kibana:
+	@{ \
+		printf "Waiting for Kibana..."; \
+		until docker inspect kibana > /dev/null 2>&1 && [[ `docker inspect -f '{{ .State.Health.Status }}' kibana` == "healthy" ]]; do printf '.'; sleep 5; done; \
+		printf "\nOpen dashboard at <http://localhost:5601/app/kibana#/dashboard/140b5490-5fce-11ea-a238-bf5970186390>\n"; \
+	}
+
+load_kibana_dashboard:
+	@{ \
+		curl -s -S -X POST -H 'kbn-xsrf: true' 'http://localhost:5601/api/saved_objects/_import?overwrite=true' --form file=@etc/kibana-objects.ndjson > /dev/null; \
+	}
+
+save_kibana_dashboard:
+	@{ \
+		curl -s -S -X POST -H 'Content-Type: application/json' -H 'kbn-xsrf: true' -o './etc/kibana-objects.ndjson' 'http://localhost:5601/api/saved_objects/_export' -d ' \
+{ \
+  "objects": [ \
+  { "type": "index-pattern", "id": "stocks-index-pattern" }, \
+  { "type": "dashboard",     "id": "140b5490-5fce-11ea-a238-bf5970186390" } \
+  ], \
+  "includeReferencesDeep": true \
+}'; \
+	}
+
+.PHONY: test setup run clean stack status wait_for_kibana load_kibana_dashboard save_kibana_dashboard
diff --git a/_examples/bulk/kafka/README.md b/_examples/bulk/kafka/README.md
new file mode 100644
index 0000000000..5b1af7d1d8
--- /dev/null
+++ b/_examples/bulk/kafka/README.md
@@ -0,0 +1,19 @@
+# Example: Bulk indexing from a Kafka topic
+
+This example demonstrates using the `BulkIndexer` component to ingest data consumed from a Kafka topic.
+
+The provided `docker-compose.yml` file launches a realistic environment with Zookeeper, Kafka, Confluent Control Center, Elasticsearch and Kibana, and allows to inspect data flows, indexer metrics, and see the ingested data in a dashboard.
+
+![Screenshot](screenshot.png)
+
+First, launch the environment and wait until it's ready:
+
+    make setup
+
+Then, launch the Kafka producers and consumers and the Elasticsearch indexer:
+
+    make run
+
+Open the [_Kibana_ dashboard](http://localhost:5601/app/kibana#/dashboard/140b5490-5fce-11ea-a238-bf5970186390) to see the results, the [_Kibana_ APM application](http://localhost:5601/app/apm#/services/kafka/transactions?rangeFrom=now-15m&rangeTo=now&refreshPaused=true&refreshInterval=0&transactionType=indexing) to see the indexer metrics, and [_Confluent Control Center_](http://localhost:9021/) to inspect the Kafka cluster and see details about the topic and performance of consumers.
+
+See the [`producer/producer.go`](producer/producer.go) file for the Kafka producer, [`consumer/consumer.go`](consumer/consumer.go) for the Kafka consumer, and the [`kafka.go`](kafka.go) file for the main workflow. The default configuration will launch one producer, four consumers, one indexer, and will send 1,000 messages per second; see `go run kafka.go --help` for changing the defaults.
diff --git a/_examples/bulk/kafka/consumer/consumer.go b/_examples/bulk/kafka/consumer/consumer.go
new file mode 100644
index 0000000000..6fc504ceb0
--- /dev/null
+++ b/_examples/bulk/kafka/consumer/consumer.go
@@ -0,0 +1,132 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package consumer
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/segmentio/kafka-go"
+
+	"go.elastic.co/apm"
+
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+type Consumer struct {
+	BrokerURL string
+	TopicName string
+
+	Indexer esutil.BulkIndexer
+	reader  *kafka.Reader
+
+	startTime     time.Time
+	totalMessages int64
+	totalErrors   int64
+	totalBytes    int64
+}
+
+func (c *Consumer) Run(ctx context.Context) (err error) {
+	if c.Indexer == nil {
+		panic(fmt.Sprintf("%T.Indexer is nil", c))
+	}
+	c.startTime = time.Now()
+
+	c.reader = kafka.NewReader(kafka.ReaderConfig{
+		Brokers: []string{c.BrokerURL},
+		GroupID: "go-elasticsearch-demo",
+		Topic:   c.TopicName,
+		// MinBytes: 1e+6, // 1MB
+		// MaxBytes: 5e+6, // 5MB
+
+		ReadLagInterval: 1 * time.Second,
+	})
+
+	for {
+		msg, err := c.reader.ReadMessage(ctx)
+		if err != nil {
+			return fmt.Errorf("reader: %s", err)
+		}
+		// log.Printf("%v/%v/%v:%s\n", msg.Topic, msg.Partition, msg.Offset, string(msg.Value))
+
+		if err := c.Indexer.Add(ctx,
+			esutil.BulkIndexerItem{
+				Action: "create",
+				Body:   bytes.NewReader(msg.Value),
+				OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
+					// log.Printf("Indexed %s/%s", res.Index, res.DocumentID)
+				},
+				OnFailure: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem, err error) {
+					if err != nil {
+						apm.CaptureError(ctx, err).Send()
+					} else {
+						if res.Error.Type != "" {
+							// log.Printf("%s:%s", res.Error.Type, res.Error.Reason)
+							// apm.CaptureError(ctx, fmt.Errorf("%s:%s", res.Error.Type, res.Error.Reason)).Send()
+						} else {
+							// log.Printf("%s/%s %s (%d)", res.Index, res.DocumentID, res.Result, res.Status)
+							// apm.CaptureError(ctx, fmt.Errorf("%s/%s %s (%d)", res.Index, res.DocumentID, res.Result, res.Status)).Send()
+						}
+
+					}
+				},
+			}); err != nil {
+			apm.DefaultTracer.NewError(err).Send()
+			return fmt.Errorf("indexer: %s", err)
+		}
+	}
+	c.reader.Close()
+	c.Indexer.Close(ctx)
+
+	return nil
+}
+
+type Stats struct {
+	Duration      time.Duration
+	TotalLag      int64
+	TotalMessages int64
+	TotalErrors   int64
+	TotalBytes    int64
+	Throughput    float64
+}
+
+func (c *Consumer) Stats() Stats {
+	if c.reader == nil || c.Indexer == nil {
+		return Stats{}
+	}
+
+	duration := time.Since(c.startTime)
+	readerStats := c.reader.Stats()
+
+	c.totalMessages += readerStats.Messages
+	c.totalErrors += readerStats.Errors
+	c.totalBytes += readerStats.Bytes
+
+	rate := float64(c.totalMessages) / duration.Seconds()
+
+	return Stats{
+		Duration:      duration,
+		TotalLag:      readerStats.Lag,
+		TotalMessages: c.totalMessages,
+		TotalErrors:   c.totalErrors,
+		TotalBytes:    c.totalBytes,
+		Throughput:    rate,
+	}
+}
diff --git a/_examples/bulk/kafka/docker-compose.yml b/_examples/bulk/kafka/docker-compose.yml
new file mode 100644
index 0000000000..30d439b264
--- /dev/null
+++ b/_examples/bulk/kafka/docker-compose.yml
@@ -0,0 +1,129 @@
+version: "3.7"
+
+services:
+  zookeeper:
+    container_name: zookeeper
+    image: confluentinc/cp-zookeeper:${CONFLUENT_VERSION}
+    networks:
+      - kafka
+    environment:
+      ZOOKEEPER_SERVER_ID: 1
+      ZOOKEEPER_CLIENT_PORT: 2181
+      ZOOKEEPER_TICK_TIME: 2000
+      KAFKA_OPTS: '-Dzookeeper.4lw.commands.whitelist=ruok'
+    healthcheck:
+      test: echo "ruok" | nc localhost 2181 | grep "imok"
+
+  kafka:
+    container_name: kafka
+    image: confluentinc/cp-server:${CONFLUENT_VERSION}
+    depends_on:
+      - zookeeper
+    ports:
+      # NOTE: Use kafka:29092 for connections within Docker
+     - 9092:9092
+    networks:
+      - kafka
+    volumes:
+      - kafka-data:/var/lib/kafka/data
+    environment:
+      KAFKA_BROKER_ID: 1
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_HEAP_OPTS: '-Xms${KAFKA_MEMORY} -Xmx${KAFKA_MEMORY}'
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
+      KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
+      KAFKA_METRIC_REPORTERS: io.confluent.metrics.reporter.ConfluentMetricsReporter
+      KAFKA_LOG4J_ROOT_LOGLEVEL: WARN
+      KAFKA_TOOLS_LOG4J_LOGLEVEL: ERROR
+      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 100
+      KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR: 1
+      CONFLUENT_METRICS_REPORTER_BOOTSTRAP_SERVERS: kafka:29092
+      CONFLUENT_METRICS_REPORTER_ZOOKEEPER_CONNECT: zookeeper:2181
+      CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS: 1
+      CONFLUENT_METRICS_ENABLE: 'true'
+    restart: on-failure
+    healthcheck:
+      test: nc -z localhost 9092
+
+  control-center:
+    container_name: control-center
+    image: confluentinc/cp-enterprise-control-center:${CONFLUENT_VERSION}
+    hostname: control-center
+    depends_on:
+      - zookeeper
+      - kafka
+    ports:
+      - 9021:9021
+    networks:
+      - kafka
+    environment:
+      CONTROL_CENTER_BOOTSTRAP_SERVERS: 'kafka:29092'
+      CONTROL_CENTER_ZOOKEEPER_CONNECT: 'zookeeper:2181'
+      CONTROL_CENTER_REPLICATION_FACTOR: 1
+      CONTROL_CENTER_INTERNAL_TOPICS_PARTITIONS: 1
+      CONTROL_CENTER_MONITORING_INTERCEPTOR_TOPIC_PARTITIONS: 1
+      CONFLUENT_METRICS_TOPIC_REPLICATION: 1
+      PORT: 9021
+    ulimits: { nofile: { soft: 16384, hard: 16384 } }
+    healthcheck:
+      test: curl --head --max-time 120 --retry 120 --retry-delay 1 --show-error --silent http://localhost:9021
+
+  elasticsearch:
+    container_name: elasticsearch
+    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION}
+    volumes:
+      - es-data:/usr/share/elasticsearch/data
+    networks:
+      - elasticsearch
+    ports:
+      - 9200:9200
+    environment:
+      - node.name=elasticsearch
+      - cluster.name=go-elasticsearch-kafka-demo
+      - cluster.initial_master_nodes=elasticsearch
+      - discovery.seed_hosts=elasticsearch
+      - network.host=elasticsearch,_local_
+      - network.publish_host=elasticsearch
+      - bootstrap.memory_lock=true
+      - ES_JAVA_OPTS=-Xms${ES_MEMORY} -Xmx${ES_MEMORY}
+    ulimits: { nofile: { soft: 65535, hard: 65535 }, memlock: -1 }
+    healthcheck:
+      test: curl --head --max-time 120 --retry 120 --retry-delay 1 --show-error --silent http://localhost:9200
+
+  kibana:
+    container_name: kibana
+    image: docker.elastic.co/kibana/kibana:${ELASTIC_VERSION}
+    depends_on: ['elasticsearch']
+    networks:
+      - elasticsearch
+    ports:
+      - 5601:5601
+    environment:
+      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
+      - KIBANA_LOGGING_QUIET=true
+    healthcheck:
+      test: curl --max-time 120 --retry 120 --retry-delay 1 --show-error --silent http://localhost:5601
+
+  apm_server:
+    container_name: apm_server
+    image: docker.elastic.co/apm/apm-server:${ELASTIC_VERSION}
+    depends_on: ['elasticsearch', 'kibana']
+    command: -e --strict.perms=false
+    networks:
+      - elasticsearch
+    ports:
+      - 8200:8200
+    restart: on-failure
+    healthcheck:
+      test: curl --max-time 120 --retry 120 --retry-delay 1 --show-error --silent http://localhost:8200
+
+networks:
+  kafka:
+  elasticsearch:
+
+volumes:
+  kafka-data:
+  es-data:
diff --git a/_examples/bulk/kafka/etc/kibana-objects.ndjson b/_examples/bulk/kafka/etc/kibana-objects.ndjson
new file mode 100644
index 0000000000..febc50d7f1
--- /dev/null
+++ b/_examples/bulk/kafka/etc/kibana-objects.ndjson
@@ -0,0 +1,8 @@
+{"attributes":{"fields":"[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"account\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"amount\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"price\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"quantity\",\"type\":\"number\",\"esTypes\":[\"long\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"side\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"symbol\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"time\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","timeFieldName":"time","title":"stocks*"},"id":"stocks-index-pattern","migrationVersion":{"index-pattern":"7.6.0"},"references":[],"type":"index-pattern","updated_at":"2020-03-08T07:16:40.796Z","version":"WzMsMV0="}
+{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"Timeline","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Timeline\",\"type\":\"metrics\",\"params\":{\"annotations\":[{\"color\":\"#F00\",\"fields\":\"\",\"icon\":\"fa-tag\",\"id\":\"a9a38ce0-5fc7-11ea-9dfe-a575a96938ae\",\"ignore_global_filters\":1,\"ignore_panel_filters\":1,\"index_pattern\":\"\",\"query_string\":{\"language\":\"kuery\",\"query\":\"\"},\"template\":\"\"}],\"axis_formatter\":\"number\",\"axis_position\":\"left\",\"axis_scale\":\"normal\",\"background_color_rules\":[{\"id\":\"1b1b3fd0-5fc8-11ea-9dfe-a575a96938ae\"}],\"bar_color_rules\":[{\"id\":\"1e32b900-5fc8-11ea-9dfe-a575a96938ae\"}],\"default_index_pattern\":\"stocks*\",\"default_timefield\":\"time\",\"gauge_color_rules\":[{\"id\":\"1fcbcf90-5fc8-11ea-9dfe-a575a96938ae\"}],\"gauge_inner_width\":10,\"gauge_style\":\"half\",\"gauge_width\":10,\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"index_pattern\":\"stocks\",\"interval\":\"\",\"isModelInvalid\":false,\"series\":[{\"axis_position\":\"right\",\"chart_type\":\"bar\",\"color\":\"rgba(0,84,188,1)\",\"fill\":0.5,\"formatter\":\"number\",\"hidden\":false,\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"label\":\"Trades\",\"line_width\":1,\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"point_size\":1,\"separate_axis\":0,\"split_mode\":\"everything\",\"stacked\":\"none\",\"terms_field\":\"symbol\",\"axis_min\":\"0\",\"axis_max\":\"1000\",\"type\":\"timeseries\"},{\"axis_position\":\"right\",\"chart_type\":\"line\",\"color\":\"rgba(211,192,91,0.65)\",\"fill\":0.5,\"formatter\":\"number\",\"hidden\":false,\"id\":\"c0f53f10-5fc7-11ea-9dfe-a575a96938ae\",\"label\":\"Volume\",\"line_width\":1,\"metrics\":[{\"field\":\"amount\",\"id\":\"c0f53f11-5fc7-11ea-9dfe-a575a96938ae\",\"percentiles\":[{\"id\":\"3049f580-5fc9-11ea-9dfe-a575a96938ae\",\"mode\":\"line\",\"shade\":0.2,\"value\":50}],\"type\":\"sum\"}],\"point_size\":1,\"separate_axis\":1,\"split_mode\":\"everything\",\"stacked\":\"none\",\"terms_field\":\"symbol\",\"type\":\"timeseries\",\"value_template\":\"${{value}}\"},{\"id\":\"c6e77fa0-6111-11ea-a5d2-d3bd7837d38b\",\"color\":\"rgba(25,77,51,1)\",\"split_mode\":\"filter\",\"metrics\":[{\"id\":\"c6e77fa1-6111-11ea-a5d2-d3bd7837d38b\",\"type\":\"avg\",\"field\":\"price\"}],\"separate_axis\":1,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"00\",\"fill\":\"0\",\"stacked\":\"none\",\"label\":\"Buy\",\"type\":\"timeseries\",\"terms_field\":\"side\",\"terms_size\":\"2\",\"terms_order_by\":\"_key\",\"value_template\":\"${{value}}\",\"filter\":{\"query\":\"side : \\\"BUY\\\" \",\"language\":\"kuery\"}},{\"id\":\"5f562c50-6112-11ea-a5d2-d3bd7837d38b\",\"color\":\"rgba(159,5,0,1)\",\"split_mode\":\"filter\",\"metrics\":[{\"id\":\"5f593990-6112-11ea-a5d2-d3bd7837d38b\",\"type\":\"avg\",\"field\":\"price\"}],\"separate_axis\":1,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":\"00\",\"fill\":\"0\",\"stacked\":\"none\",\"label\":\"Sell\",\"type\":\"timeseries\",\"terms_field\":\"side\",\"terms_size\":\"2\",\"terms_order_by\":\"_key\",\"value_template\":\"${{value}}\",\"filter\":{\"query\":\"side : \\\"SELL\\\"  \",\"language\":\"kuery\"}}],\"show_grid\":1,\"show_legend\":1,\"time_field\":\"time\",\"type\":\"timeseries\",\"pivot_id\":\"symbol\",\"pivot_type\":\"string\",\"pivot_label\":\"Symbol\"},\"aggs\":[]}"},"id":"ba131000-5fcc-11ea-a238-bf5970186390","migrationVersion":{"visualization":"7.4.2"},"references":[],"type":"visualization","updated_at":"2020-03-08T08:46:43.866Z","version":"WzkzMSwxXQ=="}
+{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Trades by Side","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Trades by Side\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":true,\"values\":false,\"last_level\":false,\"truncate\":50}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"side\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":2,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"id":"e96fbcd0-5fcd-11ea-a238-bf5970186390","migrationVersion":{"visualization":"7.4.2"},"references":[{"id":"stocks-index-pattern","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2020-03-08T07:47:00.842Z","version":"WzMwNSwxXQ=="}
+{"attributes":{"expression":"kibana\n| kibana_context  query=\"{\\\"query\\\":\\\"\\\",\\\"language\\\":\\\"kuery\\\"}\" filters=\"[]\"\n| lens_merge_tables layerIds=\"c234107c-d568-4988-bc9c-e8a2f3976f71\" \n  tables={esaggs index=\"stocks-index-pattern\" metricsAtAllLevels=false partialRows=false includeFormatHints=true aggConfigs={lens_auto_date aggConfigs=\"[{\\\"id\\\":\\\"7e7c15ce-c564-40d0-95f1-e2e768effb24\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"terms\\\",\\\"schema\\\":\\\"segment\\\",\\\"params\\\":{\\\"field\\\":\\\"account\\\",\\\"orderBy\\\":\\\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\",\\\"order\\\":\\\"desc\\\",\\\"size\\\":10,\\\"otherBucket\\\":false,\\\"otherBucketLabel\\\":\\\"Other\\\",\\\"missingBucket\\\":false,\\\"missingBucketLabel\\\":\\\"Missing\\\"}},{\\\"id\\\":\\\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"count\\\",\\\"schema\\\":\\\"metric\\\",\\\"params\\\":{}}]\"} | lens_rename_columns idMap=\"{\\\"col-0-7e7c15ce-c564-40d0-95f1-e2e768effb24\\\":{\\\"label\\\":\\\"Accounts\\\",\\\"dataType\\\":\\\"string\\\",\\\"operationType\\\":\\\"terms\\\",\\\"scale\\\":\\\"ordinal\\\",\\\"sourceField\\\":\\\"account\\\",\\\"isBucketed\\\":true,\\\"params\\\":{\\\"size\\\":10,\\\"orderBy\\\":{\\\"type\\\":\\\"column\\\",\\\"columnId\\\":\\\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\"},\\\"orderDirection\\\":\\\"desc\\\"},\\\"id\\\":\\\"7e7c15ce-c564-40d0-95f1-e2e768effb24\\\"},\\\"col-1-3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\":{\\\"label\\\":\\\"Trades\\\",\\\"dataType\\\":\\\"number\\\",\\\"operationType\\\":\\\"count\\\",\\\"isBucketed\\\":false,\\\"scale\\\":\\\"ratio\\\",\\\"sourceField\\\":\\\"Records\\\",\\\"id\\\":\\\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\"}}\"}\n| lens_xy_chart xTitle=\"Accounts\" yTitle=\"Trades\" legend={lens_xy_legendConfig isVisible=true position=\"right\"} \n  layers={lens_xy_layer layerId=\"c234107c-d568-4988-bc9c-e8a2f3976f71\" hide=false xAccessor=\"7e7c15ce-c564-40d0-95f1-e2e768effb24\" yScaleType=\"linear\" xScaleType=\"ordinal\" isHistogram=false splitAccessor=undefined seriesType=\"bar_horizontal\" accessors=\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\" columnToLabel=\"{\\\"3c6e3bde-20c2-4f82-92fd-6b8a664558e5\\\":\\\"Trades\\\"}\"}","state":{"datasourceMetaData":{"filterableIndexPatterns":[{"id":"stocks-index-pattern","title":"stocks*"}]},"datasourceStates":{"indexpattern":{"currentIndexPatternId":"stocks-index-pattern","layers":{"c234107c-d568-4988-bc9c-e8a2f3976f71":{"columnOrder":["7e7c15ce-c564-40d0-95f1-e2e768effb24","3c6e3bde-20c2-4f82-92fd-6b8a664558e5"],"columns":{"3c6e3bde-20c2-4f82-92fd-6b8a664558e5":{"dataType":"number","isBucketed":false,"label":"Trades","operationType":"count","scale":"ratio","sourceField":"Records"},"7e7c15ce-c564-40d0-95f1-e2e768effb24":{"dataType":"string","isBucketed":true,"label":"Accounts","operationType":"terms","params":{"orderBy":{"columnId":"3c6e3bde-20c2-4f82-92fd-6b8a664558e5","type":"column"},"orderDirection":"desc","size":10},"scale":"ordinal","sourceField":"account"}},"indexPatternId":"stocks-index-pattern"}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"accessors":["3c6e3bde-20c2-4f82-92fd-6b8a664558e5","0ce4f43c-6b35-4e60-b6a9-cdc9bbc473e2"],"layerId":"c234107c-d568-4988-bc9c-e8a2f3976f71","position":"top","seriesType":"bar_horizontal","showGridlines":false,"splitAccessor":"62b36bc8-ea6b-49ef-8940-9da3865b3173","xAccessor":"7e7c15ce-c564-40d0-95f1-e2e768effb24"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_horizontal"}},"title":"Trades by Account","visualizationType":"lnsXY"},"id":"fb7a9910-5fd5-11ea-9216-cffe4a4e87d2","references":[],"type":"lens","updated_at":"2020-03-08T07:16:40.796Z","version":"WzYsMV0="}
+{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Symbols by Amount","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Symbols by Amount\",\"type\":\"horizontal_bar\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":false,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":false,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"Amount\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Amount\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"bottom\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"metric\",\"params\":{\"field\":\"amount\",\"customLabel\":\"Amount\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"symbol\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Symbol\",\"row\":true}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"side\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"id":"f7bdf800-610e-11ea-b327-61404d5d790e","migrationVersion":{"visualization":"7.4.2"},"references":[{"id":"stocks-index-pattern","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"visualization","updated_at":"2020-03-08T07:32:30.208Z","version":"WzE1MywxXQ=="}
+{"attributes":{"expression":"kibana\n| kibana_context  query=\"{\\\"query\\\":\\\"\\\",\\\"language\\\":\\\"kuery\\\"}\" filters=\"[]\"\n| lens_merge_tables layerIds=\"076198d9-6805-4272-b37c-4bccd5c1594b\" \n  tables={esaggs index=\"stocks-index-pattern\" metricsAtAllLevels=false partialRows=false includeFormatHints=true aggConfigs={lens_auto_date aggConfigs=\"[{\\\"id\\\":\\\"13b859ef-3659-4cad-a001-ec895e8d6767\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"terms\\\",\\\"schema\\\":\\\"segment\\\",\\\"params\\\":{\\\"field\\\":\\\"symbol\\\",\\\"orderBy\\\":\\\"_key\\\",\\\"order\\\":\\\"asc\\\",\\\"size\\\":10,\\\"otherBucket\\\":false,\\\"otherBucketLabel\\\":\\\"Other\\\",\\\"missingBucket\\\":false,\\\"missingBucketLabel\\\":\\\"Missing\\\"}},{\\\"id\\\":\\\"69896c33-5403-4874-86c2-a113ff715d9c\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"date_histogram\\\",\\\"schema\\\":\\\"segment\\\",\\\"params\\\":{\\\"field\\\":\\\"time\\\",\\\"useNormalizedEsInterval\\\":true,\\\"interval\\\":\\\"auto\\\",\\\"drop_partials\\\":false,\\\"min_doc_count\\\":0,\\\"extended_bounds\\\":{}}},{\\\"id\\\":\\\"3cff11c2-a9d1-46bc-b317-247f9cb734bc\\\",\\\"enabled\\\":true,\\\"type\\\":\\\"sum\\\",\\\"schema\\\":\\\"metric\\\",\\\"params\\\":{\\\"field\\\":\\\"amount\\\",\\\"missing\\\":0}}]\"} | lens_rename_columns idMap=\"{\\\"col-0-13b859ef-3659-4cad-a001-ec895e8d6767\\\":{\\\"dataType\\\":\\\"string\\\",\\\"isBucketed\\\":true,\\\"label\\\":\\\"Top values of symbol\\\",\\\"operationType\\\":\\\"terms\\\",\\\"params\\\":{\\\"orderBy\\\":{\\\"type\\\":\\\"alphabetical\\\"},\\\"orderDirection\\\":\\\"asc\\\",\\\"size\\\":10},\\\"scale\\\":\\\"ordinal\\\",\\\"sourceField\\\":\\\"symbol\\\",\\\"id\\\":\\\"13b859ef-3659-4cad-a001-ec895e8d6767\\\"},\\\"col-1-69896c33-5403-4874-86c2-a113ff715d9c\\\":{\\\"dataType\\\":\\\"date\\\",\\\"isBucketed\\\":true,\\\"label\\\":\\\"Time\\\",\\\"operationType\\\":\\\"date_histogram\\\",\\\"params\\\":{\\\"interval\\\":\\\"auto\\\"},\\\"scale\\\":\\\"interval\\\",\\\"sourceField\\\":\\\"time\\\",\\\"id\\\":\\\"69896c33-5403-4874-86c2-a113ff715d9c\\\"},\\\"col-2-3cff11c2-a9d1-46bc-b317-247f9cb734bc\\\":{\\\"dataType\\\":\\\"number\\\",\\\"isBucketed\\\":false,\\\"label\\\":\\\"Volume\\\",\\\"operationType\\\":\\\"sum\\\",\\\"scale\\\":\\\"ratio\\\",\\\"sourceField\\\":\\\"amount\\\",\\\"id\\\":\\\"3cff11c2-a9d1-46bc-b317-247f9cb734bc\\\"}}\"}\n| lens_xy_chart xTitle=\"Time\" yTitle=\"Volume\" legend={lens_xy_legendConfig isVisible=true position=\"right\"} \n  layers={lens_xy_layer layerId=\"076198d9-6805-4272-b37c-4bccd5c1594b\" hide=false xAccessor=\"69896c33-5403-4874-86c2-a113ff715d9c\" yScaleType=\"linear\" xScaleType=\"time\" isHistogram=true splitAccessor=\"13b859ef-3659-4cad-a001-ec895e8d6767\" seriesType=\"bar_stacked\" accessors=\"3cff11c2-a9d1-46bc-b317-247f9cb734bc\" columnToLabel=\"{\\\"3cff11c2-a9d1-46bc-b317-247f9cb734bc\\\":\\\"Volume\\\",\\\"13b859ef-3659-4cad-a001-ec895e8d6767\\\":\\\"Top values of symbol\\\"}\"}","state":{"datasourceMetaData":{"filterableIndexPatterns":[{"id":"stocks-index-pattern","title":"stocks*"}]},"datasourceStates":{"indexpattern":{"currentIndexPatternId":"stocks-index-pattern","layers":{"076198d9-6805-4272-b37c-4bccd5c1594b":{"columnOrder":["13b859ef-3659-4cad-a001-ec895e8d6767","69896c33-5403-4874-86c2-a113ff715d9c","3cff11c2-a9d1-46bc-b317-247f9cb734bc"],"columns":{"13b859ef-3659-4cad-a001-ec895e8d6767":{"dataType":"string","isBucketed":true,"label":"Top values of symbol","operationType":"terms","params":{"orderBy":{"type":"alphabetical"},"orderDirection":"asc","size":10},"scale":"ordinal","sourceField":"symbol"},"3cff11c2-a9d1-46bc-b317-247f9cb734bc":{"dataType":"number","isBucketed":false,"label":"Volume","operationType":"sum","scale":"ratio","sourceField":"amount"},"69896c33-5403-4874-86c2-a113ff715d9c":{"dataType":"date","isBucketed":true,"label":"Time","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"time"}},"indexPatternId":"stocks-index-pattern"}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"accessors":["3cff11c2-a9d1-46bc-b317-247f9cb734bc","db3f5244-b217-4140-8f3e-5492fb247555"],"layerId":"076198d9-6805-4272-b37c-4bccd5c1594b","position":"top","seriesType":"bar_stacked","showGridlines":false,"splitAccessor":"13b859ef-3659-4cad-a001-ec895e8d6767","xAccessor":"69896c33-5403-4874-86c2-a113ff715d9c"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_stacked"}},"title":"Symbols by Time","visualizationType":"lnsXY"},"id":"55903530-5fcd-11ea-a238-bf5970186390","references":[],"type":"lens","updated_at":"2020-03-08T08:45:59.329Z","version":"WzkxNywxXQ=="}
+{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"8.0.0-SNAPSHOT\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":9,\"i\":\"be2ff307-1383-4896-be32-3bf41b175629\"},\"panelIndex\":\"be2ff307-1383-4896-be32-3bf41b175629\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0-SNAPSHOT\",\"gridData\":{\"x\":0,\"y\":9,\"w\":10,\"h\":10,\"i\":\"b31d60e9-8b89-46d2-833b-5db3e143cc4d\"},\"panelIndex\":\"b31d60e9-8b89-46d2-833b-5db3e143cc4d\",\"embeddableConfig\":{\"vis\":{\"legendOpen\":false}},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0-SNAPSHOT\",\"gridData\":{\"x\":10,\"y\":9,\"w\":11,\"h\":10,\"i\":\"5db3a824-52dc-49e1-b6d1-20736db0f572\"},\"panelIndex\":\"5db3a824-52dc-49e1-b6d1-20736db0f572\",\"embeddableConfig\":{},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0-SNAPSHOT\",\"gridData\":{\"x\":21,\"y\":9,\"w\":11,\"h\":10,\"i\":\"5488f083-7d67-49f7-9d7e-1fe576cf13ef\"},\"panelIndex\":\"5488f083-7d67-49f7-9d7e-1fe576cf13ef\",\"embeddableConfig\":{\"vis\":{\"legendOpen\":false}},\"panelRefName\":\"panel_3\"},{\"version\":\"8.0.0-SNAPSHOT\",\"gridData\":{\"x\":32,\"y\":9,\"w\":16,\"h\":10,\"i\":\"5cc46a50-9ead-493d-accf-7ff80ed7df0b\"},\"panelIndex\":\"5cc46a50-9ead-493d-accf-7ff80ed7df0b\",\"embeddableConfig\":{},\"panelRefName\":\"panel_4\"}]","refreshInterval":{"pause":false,"value":5000},"timeFrom":"now-15m","timeRestore":true,"timeTo":"now","title":"Stocks","version":1},"id":"140b5490-5fce-11ea-a238-bf5970186390","migrationVersion":{"dashboard":"7.3.0"},"references":[{"id":"ba131000-5fcc-11ea-a238-bf5970186390","name":"panel_0","type":"visualization"},{"id":"e96fbcd0-5fcd-11ea-a238-bf5970186390","name":"panel_1","type":"visualization"},{"id":"fb7a9910-5fd5-11ea-9216-cffe4a4e87d2","name":"panel_2","type":"lens"},{"id":"f7bdf800-610e-11ea-b327-61404d5d790e","name":"panel_3","type":"visualization"},{"id":"55903530-5fcd-11ea-a238-bf5970186390","name":"panel_4","type":"lens"}],"type":"dashboard","updated_at":"2020-03-08T08:05:52.292Z","version":"WzcyNCwxXQ=="}
+{"exportedCount":7,"missingRefCount":0,"missingReferences":[]}
\ No newline at end of file
diff --git a/_examples/bulk/kafka/go.mod b/_examples/bulk/kafka/go.mod
new file mode 100644
index 0000000000..79382f01dc
--- /dev/null
+++ b/_examples/bulk/kafka/go.mod
@@ -0,0 +1,13 @@
+module github.com/elastic/go-elasticsearch/v7/_examples/bulk/kafka
+
+go 1.11
+
+replace github.com/elastic/go-elasticsearch/v7 => ../../..
+
+require (
+	github.com/dustin/go-humanize v1.0.0
+	github.com/elastic/go-elasticsearch/v7 7.x
+	github.com/segmentio/kafka-go v0.3.5
+	go.elastic.co/apm v1.7.1
+	go.elastic.co/apm/module/apmelasticsearch v1.7.1
+)
diff --git a/_examples/bulk/kafka/kafka.go b/_examples/bulk/kafka/kafka.go
new file mode 100644
index 0000000000..11c04e92ae
--- /dev/null
+++ b/_examples/bulk/kafka/kafka.go
@@ -0,0 +1,381 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+package main
+
+import (
+	"context"
+	"expvar"
+	"flag"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"strings"
+	"sync"
+	"time"
+
+	_ "net/http/pprof"
+
+	"github.com/dustin/go-humanize"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+
+	"go.elastic.co/apm"
+	"go.elastic.co/apm/module/apmelasticsearch"
+
+	"github.com/elastic/go-elasticsearch/v7/_examples/bulk/kafka/consumer"
+	"github.com/elastic/go-elasticsearch/v7/_examples/bulk/kafka/producer"
+)
+
+var (
+	brokerURL string
+
+	topicName  = "stocks"
+	topicParts = 4
+	msgRate    int
+
+	indexName    = "stocks"
+	numProducers = 1
+	numConsumers = 4
+	numIndexers  = 1
+	flushBytes   = 0 // Default
+	numWorkers   = 0 // Default
+	indexerError error
+
+	mapping = `{
+  "mappings": {
+    "properties": {
+    	"time":     { "type": "date"    },
+    	"symbol":   { "type": "keyword" },
+    	"side":     { "type": "keyword" },
+      "account":  { "type": "keyword" },
+      "quantity": { "type": "long"    },
+      "price":    { "type": "long"    },
+      "amount":   { "type": "long"    }
+      }
+    }}}`
+)
+
+func init() {
+	if v := os.Getenv("KAFKA_URL"); v != "" {
+		brokerURL = v
+	} else {
+		brokerURL = "localhost:9092"
+	}
+	flag.IntVar(&msgRate, "rate", 1000, "Producer rate (msg/sec)")
+	flag.IntVar(&numProducers, "producers", numProducers, "Number of producers")
+	flag.IntVar(&numConsumers, "consumers", numConsumers, "Number of consumers")
+	flag.IntVar(&numIndexers, "indexers", numIndexers, "Number of indexers")
+	flag.Parse()
+}
+
+func main() {
+	log.SetFlags(0)
+
+	// Serve the "/debug/pprof/" and "/debug/vars" pages
+	//
+	go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
+
+	var (
+		wg  sync.WaitGroup
+		ctx = context.Background()
+
+		producers []*producer.Producer
+		consumers []*consumer.Consumer
+		indexers  []esutil.BulkIndexer
+	)
+
+	done := make(chan os.Signal)
+	signal.Notify(done, os.Interrupt)
+	go func() { <-done; log.Println("\n"); os.Exit(0) }()
+
+	// Set up producers
+	//
+	for i := 1; i <= numProducers; i++ {
+		producers = append(producers,
+			&producer.Producer{
+				BrokerURL:   brokerURL,
+				TopicName:   topicName,
+				TopicParts:  topicParts,
+				MessageRate: msgRate})
+	}
+
+	// Create an Elasticsearch client
+	//
+	es, err := elasticsearch.NewClient(elasticsearch.Config{
+		RetryOnStatus: []int{502, 503, 504, 429}, // Add 429 to the list of retryable statuses
+		RetryBackoff:  func(i int) time.Duration { return time.Duration(i) * 100 * time.Millisecond },
+		MaxRetries:    5,
+		EnableMetrics: true,
+		Transport:     apmelasticsearch.WrapRoundTripper(http.DefaultTransport),
+	})
+	if err != nil {
+		log.Fatalf("Error: NewClient(): %s", err)
+	}
+	// Export client metrics to the "expvar" package
+	expvar.Publish("go-elasticsearch", expvar.Func(func() interface{} { m, _ := es.Metrics(); return m }))
+
+	// Create the "stocks" index with correct mappings
+	//
+	res, err := es.Indices.Exists([]string{indexName})
+	if err != nil {
+		log.Fatalf("Error: Indices.Exists: %s", err)
+	}
+	res.Body.Close()
+	if res.StatusCode == 404 {
+		res, err := es.Indices.Create(
+			indexName,
+			es.Indices.Create.WithBody(strings.NewReader(mapping)),
+			es.Indices.Create.WithWaitForActiveShards("1"),
+		)
+		if err != nil {
+			log.Fatalf("Error: Indices.Create: %s", err)
+		}
+		if res.IsError() {
+			log.Fatalf("Error: Indices.Create: %s", res)
+		}
+	}
+
+	// Set up indexers
+	//
+	for i := 1; i <= numIndexers; i++ {
+		idx, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+			Index:      indexName,
+			Client:     es,
+			NumWorkers: numWorkers,
+			FlushBytes: int(flushBytes),
+			// Elastic APM: Instrument the flush operations and capture errors
+			OnFlushStart: func(ctx context.Context) context.Context {
+				txn := apm.DefaultTracer.StartTransaction("Bulk", "indexing")
+				return apm.ContextWithTransaction(ctx, txn)
+			},
+			OnFlushEnd: func(ctx context.Context) {
+				apm.TransactionFromContext(ctx).End()
+			},
+			OnError: func(ctx context.Context, err error) {
+				indexerError = err
+				apm.CaptureError(ctx, err).Send()
+			},
+		})
+		if err != nil {
+			log.Fatalf("ERROR: NewBulkIndexer(): %s", err)
+		}
+		indexers = append(indexers, idx)
+	}
+
+	// Set up consumers
+	//
+	for i := 1; i <= numConsumers; i++ {
+		consumers = append(consumers,
+			&consumer.Consumer{
+				BrokerURL: brokerURL,
+				TopicName: topicName,
+				Indexer:   indexers[i%numIndexers]})
+	}
+
+	// Set up reporting output
+	//
+	reporter := time.NewTicker(500 * time.Millisecond)
+	defer reporter.Stop()
+	go func() {
+		fmt.Printf("Initializing... producers=%d consumers=%d indexers=%d\n", numProducers, numConsumers, numIndexers)
+		for {
+			select {
+			case <-reporter.C:
+				fmt.Print(report(producers, consumers, indexers))
+			}
+		}
+	}()
+	errcleaner := time.NewTicker(10 * time.Second)
+	defer errcleaner.Stop()
+	go func() {
+		for {
+			select {
+			case <-errcleaner.C:
+				indexerError = nil
+			}
+		}
+	}()
+
+	// Create the Kafka topic
+	//
+	if len(producers) > 0 {
+		if err := producers[0].CreateTopic(ctx); err != nil {
+			log.Fatalf("ERROR: Producer: %s", err)
+		}
+	}
+
+	// Launch consumers
+	//
+	for _, c := range consumers {
+		wg.Add(1)
+		go func(c *consumer.Consumer) {
+			defer wg.Done()
+			if err := c.Run(ctx); err != nil {
+				log.Fatalf("ERROR: Consumer: %s", err)
+			}
+		}(c)
+	}
+
+	// Launch producers
+	//
+	time.Sleep(5 * time.Second) // Leave some room for consumers to connect
+	for _, p := range producers {
+		wg.Add(1)
+		go func(p *producer.Producer) {
+			defer wg.Done()
+			if err := p.Run(ctx); err != nil {
+				log.Fatalf("ERROR: Producer: %s", err)
+			}
+		}(p)
+	}
+
+	wg.Wait()
+
+	fmt.Print(report(producers, consumers, indexers))
+}
+
+func report(
+	producers []*producer.Producer,
+	consumers []*consumer.Consumer,
+	indexers []esutil.BulkIndexer,
+) string {
+	var (
+		b strings.Builder
+
+		value    string
+		currRow  = 1
+		numCols  = 6
+		colWidth = 20
+
+		divider = func(last bool) {
+			fmt.Fprintf(&b, "\033[%d;0H", currRow)
+			fmt.Fprint(&b, "┣")
+			for i := 1; i <= numCols; i++ {
+				fmt.Fprint(&b, strings.Repeat("━", colWidth))
+				if last && i == 5 {
+					fmt.Fprint(&b, "┷")
+					continue
+				}
+				if i < numCols {
+					fmt.Fprint(&b, "┿")
+				}
+			}
+			fmt.Fprint(&b, "┫")
+			currRow++
+		}
+	)
+
+	fmt.Print("\033[2J\033[K")
+	fmt.Printf("\033[%d;0H", currRow)
+
+	fmt.Fprint(&b, "┏")
+	for i := 1; i <= numCols; i++ {
+		fmt.Fprint(&b, strings.Repeat("━", colWidth))
+		if i < numCols {
+			fmt.Fprint(&b, "┯")
+		}
+	}
+	fmt.Fprint(&b, "┓")
+	currRow++
+
+	for i, p := range producers {
+		fmt.Fprintf(&b, "\033[%d;0H", currRow)
+		value = fmt.Sprintf("Producer %d", i+1)
+		fmt.Fprintf(&b, "┃ %-*s│", colWidth-1, value)
+		s := p.Stats()
+		value = fmt.Sprintf("duration=%s", s.Duration.Truncate(time.Second))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("msg/sec=%s", humanize.FtoaWithDigits(s.Throughput, 2))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("sent=%s", humanize.Comma(int64(s.TotalMessages)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("bytes=%s", humanize.Bytes(uint64(s.TotalBytes)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("errors=%s", humanize.Comma(int64(s.TotalErrors)))
+		fmt.Fprintf(&b, " %-*s┃", colWidth-1, value)
+		currRow++
+		divider(i == len(producers)-1)
+	}
+
+	for i, c := range consumers {
+		fmt.Fprintf(&b, "\033[%d;0H", currRow)
+		value = fmt.Sprintf("Consumer %d", i+1)
+		fmt.Fprintf(&b, "┃ %-*s│", colWidth-1, value)
+		s := c.Stats()
+		value = fmt.Sprintf("lagging=%s", humanize.Comma(s.TotalLag))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("msg/sec=%s", humanize.FtoaWithDigits(s.Throughput, 2))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("received=%s", humanize.Comma(s.TotalMessages))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("bytes=%s", humanize.Bytes(uint64(s.TotalBytes)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("errors=%s", humanize.Comma(s.TotalErrors))
+		fmt.Fprintf(&b, " %-*s┃", colWidth-1, value)
+		currRow++
+		divider(i == len(consumers)-1)
+	}
+
+	for i, x := range indexers {
+		fmt.Fprintf(&b, "\033[%d;0H", currRow)
+		value = fmt.Sprintf("Indexer %d", i+1)
+		fmt.Fprintf(&b, "┃ %-*s│", colWidth-1, value)
+		s := x.Stats()
+		value = fmt.Sprintf("added=%s", humanize.Comma(int64(s.NumAdded)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("flushed=%s", humanize.Comma(int64(s.NumFlushed)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		value = fmt.Sprintf("failed=%s", humanize.Comma(int64(s.NumFailed)))
+		fmt.Fprintf(&b, " %-*s│", colWidth-1, value)
+		if indexerError != nil {
+			value = "err=" + indexerError.Error()
+			if len(value) > 2*colWidth {
+				value = value[:2*colWidth]
+			}
+		} else {
+			value = ""
+		}
+		fmt.Fprintf(&b, " %-*s┃", 2*colWidth, value)
+		currRow++
+		if i < len(indexers)-1 {
+			divider(true)
+		}
+	}
+
+	fmt.Fprintf(&b, "\033[%d;0H", currRow)
+	fmt.Fprint(&b, "┗")
+	for i := 1; i <= numCols; i++ {
+		fmt.Fprint(&b, strings.Repeat("━", colWidth))
+		if i == 5 {
+			fmt.Fprint(&b, "━")
+			continue
+		}
+		if i < numCols {
+			fmt.Fprint(&b, "┷")
+		}
+	}
+	fmt.Fprint(&b, "┛")
+	currRow++
+
+	return b.String()
+}
diff --git a/_examples/bulk/kafka/producer/producer.go b/_examples/bulk/kafka/producer/producer.go
new file mode 100644
index 0000000000..4ea8d075c5
--- /dev/null
+++ b/_examples/bulk/kafka/producer/producer.go
@@ -0,0 +1,200 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package producer
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"math/rand"
+	"net"
+	"time"
+
+	"github.com/segmentio/kafka-go"
+)
+
+var (
+	sides    = []string{"BUY", "SELL"}
+	symbols  = []string{"KBCU", "KBCU", "KBCU", "KJPR", "KJPR", "KSJD", "KXCV", "WRHV", "WTJB", "WMLU"}
+	accounts = []string{"ABC123", "ABC123", "ABC123", "LMN456", "LMN456", "STU789"}
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+	kafka.DefaultClientID = "go-elasticsearch-kafka-demo"
+}
+
+type Producer struct {
+	BrokerURL   string
+	TopicName   string
+	TopicParts  int
+	MessageRate int
+
+	writer *kafka.Writer
+
+	startTime     time.Time
+	totalMessages int64
+	totalErrors   int64
+	totalBytes    int64
+}
+
+func (p *Producer) Run(ctx context.Context) error {
+	var messages []kafka.Message
+	p.startTime = time.Now()
+
+	p.writer = kafka.NewWriter(kafka.WriterConfig{
+		Brokers: []string{p.BrokerURL},
+		Topic:   p.TopicName,
+	})
+
+	ticker := time.NewTicker(time.Second)
+
+	for {
+		select {
+		case t := <-ticker.C:
+			for i := 1; i <= p.MessageRate; i++ {
+				messages = append(messages, kafka.Message{Value: p.generateMessage(t)})
+			}
+			if err := p.writer.WriteMessages(ctx, messages...); err != nil {
+				messages = messages[:0]
+				return err
+			}
+			messages = messages[:0]
+		}
+	}
+
+	p.writer.Close()
+	ticker.Stop()
+
+	return nil
+}
+
+func (p *Producer) CreateTopic(ctx context.Context) error {
+	conn, err := net.Dial("tcp", p.BrokerURL)
+	if err != nil {
+		return err
+	}
+
+	return kafka.NewConn(conn, "", 0).CreateTopics(
+		kafka.TopicConfig{
+			Topic:             p.TopicName,
+			NumPartitions:     p.TopicParts,
+			ReplicationFactor: 1,
+		})
+}
+
+func (p *Producer) generateMessage(t time.Time) []byte {
+	var (
+		buf bytes.Buffer
+
+		timestamp time.Time
+		timeshift time.Duration
+		side      string
+		quantity  int
+		price     int
+		amount    int
+		symbol    string
+		account   string
+	)
+
+	timestamp = t
+	if timestamp.Minute() == 2 {
+		timeshift = -(time.Duration(time.Minute))
+	} else {
+		timeshift = time.Duration(time.Duration(rand.ExpFloat64()/2.0*100) * time.Second)
+	}
+	switch {
+	case timestamp.Minute()%5 == 0:
+		side = "SELL"
+	default:
+		if timestamp.Second()%3 == 0 {
+			side = "SELL"
+		} else {
+			side = "BUY"
+		}
+	}
+	switch {
+	case timestamp.Minute()%3 == 0:
+		quantity = rand.Intn(250) + 500
+	case timestamp.Second()%6 == 0:
+		quantity = rand.Intn(300) + 50
+	case timestamp.Second()%12 == 0:
+		quantity = rand.Intn(10) + 1
+	default:
+		quantity = rand.Intn(150) + 10
+	}
+	if side == "SELL" {
+		price = int(100.0 + 15.0*rand.NormFloat64())
+	} else {
+		price = int(250.0 + 50.0*rand.NormFloat64())
+	}
+	amount = quantity * price
+	if timestamp.Second()%4 == 0 {
+		symbol = "KXCV"
+	} else {
+		symbol = symbols[rand.Intn(len(symbols))]
+	}
+	if timestamp.Minute()%5 == 0 && timestamp.Second() > 30 {
+		account = "STU789"
+	} else {
+		account = accounts[rand.Intn(len(accounts))]
+	}
+
+	fmt.Fprintf(&buf,
+		`{"time":"%s", "symbol":"%s", "side":"%s", "quantity":%d, "price":%d, "amount":%d, "account":"%s"}`,
+		timestamp.UTC().Add(timeshift).Format(time.RFC3339),
+		symbol,
+		side,
+		quantity,
+		price,
+		amount,
+		account,
+	)
+	return buf.Bytes()
+}
+
+type Stats struct {
+	Duration      time.Duration
+	TotalMessages int64
+	TotalErrors   int64
+	TotalBytes    int64
+	Throughput    float64
+}
+
+func (p *Producer) Stats() Stats {
+	if p.writer == nil {
+		return Stats{}
+	}
+
+	duration := time.Since(p.startTime)
+	writerStats := p.writer.Stats()
+
+	p.totalMessages += writerStats.Messages
+	p.totalErrors += writerStats.Errors
+	p.totalBytes += writerStats.Bytes
+
+	rate := float64(p.totalMessages) / duration.Seconds()
+
+	return Stats{
+		Duration:      duration,
+		TotalMessages: p.totalMessages,
+		TotalErrors:   p.totalErrors,
+		TotalBytes:    p.totalBytes,
+		Throughput:    rate,
+	}
+}
diff --git a/_examples/bulk/kafka/screenshot.png b/_examples/bulk/kafka/screenshot.png
new file mode 100644
index 0000000000..5fb33ba2a8
Binary files /dev/null and b/_examples/bulk/kafka/screenshot.png differ
diff --git a/_examples/cloudfunction/.gcloudignore b/_examples/cloudfunction/.gcloudignore
old mode 100755
new mode 100644
diff --git a/_examples/cloudfunction/.gitignore b/_examples/cloudfunction/.gitignore
old mode 100755
new mode 100644
diff --git a/_examples/cloudfunction/Makefile b/_examples/cloudfunction/Makefile
old mode 100755
new mode 100644
index 05f38b4be7..b76776f554
--- a/_examples/cloudfunction/Makefile
+++ b/_examples/cloudfunction/Makefile
@@ -3,4 +3,6 @@ GO_TEST_CMD = $(if $(shell which richgo),richgo test,go test)
 test:  ## Run tests
 	$(GO_TEST_CMD) -v ./...
 
-.PHONY: test
+setup:
+
+.PHONY: test setup
diff --git a/_examples/cloudfunction/README.md b/_examples/cloudfunction/README.md
old mode 100755
new mode 100644
index 993c67eecd..2a197de497
--- a/_examples/cloudfunction/README.md
+++ b/_examples/cloudfunction/README.md
@@ -23,4 +23,4 @@ Invoke your function over HTTP:
 $ curl https://...cloudfunctions.net/clusterstatus
 ```
 
-See the **[`function.go`](./function.go)** file for implementation.
+See the **[`function.go`](./function.go)** file for implementation and the **[`function_test.go`](./function_test.go)** file for the example of implementing a mock transport for testing.
diff --git a/_examples/cloudfunction/function.go b/_examples/cloudfunction/function.go
old mode 100755
new mode 100644
index b022d0b501..29b4efa88f
--- a/_examples/cloudfunction/function.go
+++ b/_examples/cloudfunction/function.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // Package clusterstatus demonstrates using the Elasticsearch client for Go with Google Cloud Functions.
 //
 // Deploy the function with the gcloud command:
@@ -14,7 +31,7 @@
 //
 //   $ curl https://...cloudfunctions.net/clusterstatus
 //
-package clusterstatus // import "github.com/elastic/go-elasticsearch/_examples/clusterstatus"
+package clusterstatus
 
 import (
 	"encoding/json"
@@ -22,7 +39,7 @@ import (
 	"log"
 	"net/http"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 )
 
 // ES holds a reference to the Elasticsearch client
diff --git a/_examples/cloudfunction/function_test.go b/_examples/cloudfunction/function_test.go
old mode 100755
new mode 100644
index b6f3817a94..662df735a5
--- a/_examples/cloudfunction/function_test.go
+++ b/_examples/cloudfunction/function_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package clusterstatus_test
 
 import (
@@ -8,9 +25,9 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
-	"github.com/elastic/go-elasticsearch/_examples/clusterstatus"
+	"github.com/elastic/go-elasticsearch/v7/_examples/clusterstatus"
 )
 
 // Mock transport replaces the HTTP transport for tests
@@ -18,7 +35,10 @@ type MockTransport struct{}
 
 // RoundTrip returns a mock response.
 func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
-	return &http.Response{Body: ioutil.NopCloser(strings.NewReader(`{"status":"mocked"}`))}, nil
+	return &http.Response{
+		Body: ioutil.NopCloser(strings.NewReader(`{"status":"mocked"}`)),
+		Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
+	}, nil
 }
 
 func TestHealth(t *testing.T) {
diff --git a/_examples/cloudfunction/go.mod b/_examples/cloudfunction/go.mod
index f381f50545..0e4dfcf7a3 100644
--- a/_examples/cloudfunction/go.mod
+++ b/_examples/cloudfunction/go.mod
@@ -1,7 +1,7 @@
-module github.com/elastic/go-elasticsearch/_examples/clusterstatus
+module github.com/elastic/go-elasticsearch/v7/_examples/clusterstatus
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../..
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
-require github.com/elastic/go-elasticsearch master
+require github.com/elastic/go-elasticsearch/v7 v7.0.0-20190407092644-3fb2a278216b
diff --git a/_examples/cloudfunction/screenshot.png b/_examples/cloudfunction/screenshot.png
old mode 100755
new mode 100644
diff --git a/_examples/configuration.go b/_examples/configuration.go
old mode 100755
new mode 100644
index 21a4ab78fa..7544e73b99
--- a/_examples/configuration.go
+++ b/_examples/configuration.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 package main
@@ -9,7 +26,7 @@ import (
 	"net/http"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 )
 
 func main() {
diff --git a/_examples/customization.go b/_examples/customization.go
old mode 100755
new mode 100644
index f0affdaac1..f3163ae677
--- a/_examples/customization.go
+++ b/_examples/customization.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 package main
@@ -11,7 +28,7 @@ import (
 	"sync"
 	"sync/atomic"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 )
 
 // This example demonstrates how to provide a custom transport implementation to the client
@@ -21,7 +38,7 @@ import (
 // CountingTransport adds a custom header to the request, logs the information about
 // the request and response, and counts the number of requests to the client.
 //
-// Since it implements the `http.RoundTripper` interface, so it can be passed
+// Since it implements the `http.RoundTripper` interface, it can be passed
 // to the client as a custom HTTP transport implementation.
 //
 type CountingTransport struct {
@@ -57,8 +74,12 @@ func (t *CountingTransport) RoundTrip(req *http.Request) (*http.Response, error)
 func main() {
 	var wg sync.WaitGroup
 
+	// Create the custom transport.
+	//
 	tp := CountingTransport{}
 
+	// Pass the custom transport to the client.
+	//
 	es, _ := elasticsearch.NewClient(
 		elasticsearch.Config{Transport: &tp},
 	)
diff --git a/_examples/encoding/Makefile b/_examples/encoding/Makefile
index 0383a71a7c..67c0af6c29 100644
--- a/_examples/encoding/Makefile
+++ b/_examples/encoding/Makefile
@@ -3,15 +3,18 @@ GO_TEST_CMD = $(if $(shell which richgo),richgo test,go test)
 test: clean setup ## Run tests
 	go run gjson.go
 	go run easyjson.go
+	go run jsonreader.go
+
+bench: clean setup # Run benchmarks
+	go test -run=none -bench=. -benchmem benchmark_test.go
 
 setup: ## Install & Setup
 	@go get -u github.com/mailru/easyjson/...
+	@go mod tidy
+	@go mod download
 	go generate ./model
 
 clean: ## Remove artifacts
 	@rm -f model/*_easyjson.go
 
-bench: # Run benchmarks
-	go test -run=none -bench=. -benchmem benchmark_test.go
-
-.PHONY: clean setup test
+.PHONY: clean bench setup test
diff --git a/_examples/encoding/README.md b/_examples/encoding/README.md
index 55f7d9babf..2c05213b17 100644
--- a/_examples/encoding/README.md
+++ b/_examples/encoding/README.md
@@ -1,6 +1,6 @@
 # Example: encoding
 
-Examples in this folder demonstrate how to use third-party packages for JSON decoding and encoding.
+Examples in this folder demonstrate how to use helper methods and third-party packages for JSON decoding and encoding.
 
 ## `tidwall/gjson`
 
@@ -36,6 +36,18 @@ make clean setup
 go run easyjson.go
 ```
 
+## `esutil.JSONReader()`
+
+The [`esutil.JSONReader()`](../../esutil/json_reader.go) helper method takes a struct, a map,
+or any other serializable object, and converts it to JSON wrapped in a reader, for convenient
+passing to the `WithBody()` methods:
+
+```golang
+type Document struct{ Title string }
+doc := Document{Title: "Test"}
+es.Search(es.Search.WithBody(esutil.NewJSONReader(&doc)))
+```
+
 -----
 
 ### Benchmarks
@@ -45,9 +57,15 @@ Both `mailru/easyjson` and `tidwall/gjson` provide significant performance gains
 You can run the included benchmarks by executing the `make bench` command; example output below.
 
 ```
-BenchmarkSearchResults/json           30000	     45679 ns/op	    8456 B/op	      60 allocs/op
-BenchmarkSearchResults/easyjson      100000	     15612 ns/op	    7992 B/op	      52 allocs/op
-BenchmarkClusterStats/json_-_map      20000	     96808 ns/op	   31971 B/op	     391 allocs/op
-BenchmarkClusterStats/json_-_struct   30000	     59046 ns/op	   15048 B/op	      17 allocs/op
-BenchmarkClusterStats/gjson         1000000	      2119 ns/op	     264 B/op	       3 allocs/op
+BenchmarkEncode/Article_-_json         	  500000	      2969 ns/op	     856 B/op	       8 allocs/op
+BenchmarkEncode/Article_-_JSONReader   	  500000	      2957 ns/op	     920 B/op	      10 allocs/op
+BenchmarkEncode/Article_-_easyjson     	 1000000	      1089 ns/op	     736 B/op	       5 allocs/op
+BenchmarkEncode/map_-_json             	 1000000	      2074 ns/op	     720 B/op	      18 allocs/op
+BenchmarkEncode/map_-_JSONReader       	 1000000	      2168 ns/op	     784 B/op	      20 allocs/op
+
+BenchmarkDecode/Search_-_json          	   50000	     38922 ns/op	    8456 B/op	      60 allocs/op
+BenchmarkDecode/Search_-_easyjson      	  100000	     14344 ns/op	    7992 B/op	      52 allocs/op
+BenchmarkDecode/Cluster_-_json_-_map   	   20000	     85742 ns/op	   31972 B/op	     391 allocs/op
+BenchmarkDecode/Cluster_-_json_-_stc   	   30000	     50852 ns/op	   15048 B/op	      17 allocs/op
+BenchmarkDecode/Cluster_-_gjson        	 1000000	      2284 ns/op	     264 B/op	       3 allocs/op
 ```
diff --git a/_examples/encoding/benchmark_test.go b/_examples/encoding/benchmark_test.go
index 189dc893eb..49ac95cd7a 100644
--- a/_examples/encoding/benchmark_test.go
+++ b/_examples/encoding/benchmark_test.go
@@ -1,60 +1,152 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main_test
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
 	"log"
 	"testing"
+	"time"
 
 	"encoding/json"
 	"github.com/mailru/easyjson"
 	"github.com/tidwall/gjson"
 
-	"github.com/elastic/go-elasticsearch/_examples/encoding/model"
+	"github.com/elastic/go-elasticsearch/v7/_examples/encoding/model"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
 )
 
-func BenchmarkSearchResults(b *testing.B) {
+func BenchmarkEncode(b *testing.B) {
 	b.ReportAllocs()
 
-	input := fixture("testdata/response_search.json")
+	var (
+		buf bytes.Buffer
+
+		article = &model.Article{
+			ID:        1,
+			Title:     "Test",
+			Body:      "Test",
+			Published: time.Now(),
+			Author: &model.Author{
+				FirstName: "Alice",
+				LastName:  "Smith",
+			},
+		}
+
+		query = map[string]interface{}{
+			"query": map[string]interface{}{
+				"match": map[string]interface{}{
+					"title": "test",
+				},
+			},
+		}
+	)
 
-	b.Run("json", func(b *testing.B) {
+	b.Run("Article - json", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			var res model.SearchResponse
-			err := json.NewDecoder(bytes.NewReader(input.Bytes())).Decode(&res)
+			err := json.NewEncoder(&buf).Encode(article)
 			if err != nil {
 				b.Error(err)
 			}
+			buf.Reset()
 		}
 	})
 
-	b.Run("easyjson", func(b *testing.B) {
+	b.Run("Article - JSONReader", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			var res model.SearchResponse
-			err := easyjson.UnmarshalFromReader(bytes.NewReader(input.Bytes()), &res)
+			_, err := io.Copy(&buf, esutil.NewJSONReader(article))
+			if err != nil {
+				b.Error(err)
+			}
+			buf.Reset()
+		}
+	})
+
+	b.Run("Article - easyjson", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			_, err := easyjson.MarshalToWriter(article, &buf)
+			if err != nil {
+				b.Error(err)
+			}
+			buf.Reset()
+		}
+	})
+
+	b.Run("map - json", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			err := json.NewEncoder(&buf).Encode(query)
+			if err != nil {
+				b.Error(err)
+			}
+			buf.Reset()
+		}
+	})
+
+	b.Run("map - JSONReader", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			_, err := io.Copy(&buf, esutil.NewJSONReader(query))
 			if err != nil {
 				b.Error(err)
 			}
+			buf.Reset()
 		}
 	})
 }
 
-func BenchmarkClusterStats(b *testing.B) {
+func BenchmarkDecode(b *testing.B) {
 	b.ReportAllocs()
 
-	input := fixture("testdata/response_cluster_stats.json")
+	resSearch := fixture("testdata/response_search.json")
+	resClusterStats := fixture("testdata/response_cluster_stats.json")
+
+	b.Run("Search - json", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			var res model.SearchResponse
+			err := json.NewDecoder(bytes.NewReader(resSearch.Bytes())).Decode(&res)
+			if err != nil {
+				b.Error(err)
+			}
+		}
+	})
+
+	b.Run("Search - easyjson", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			var res model.SearchResponse
+			err := easyjson.UnmarshalFromReader(bytes.NewReader(resSearch.Bytes()), &res)
+			if err != nil {
+				b.Error(err)
+			}
+		}
+	})
 
-	b.Run("json - map", func(b *testing.B) {
+	b.Run("Cluster - json - map", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			var out = make(map[string]interface{})
-			err := json.NewDecoder(bytes.NewReader(input.Bytes())).Decode(&out)
+			err := json.NewDecoder(bytes.NewReader(resClusterStats.Bytes())).Decode(&out)
 			if err != nil {
 				b.Error(err)
 			}
 		}
 	})
 
-	b.Run("json - struct", func(b *testing.B) {
+	b.Run("Cluster - json - stc", func(b *testing.B) {
 		type ClusterHealthResponse struct {
 			ClusterName string `json:"cluster_name"`
 			Status      string
@@ -68,7 +160,7 @@ func BenchmarkClusterStats(b *testing.B) {
 
 		for i := 0; i < b.N; i++ {
 			var out ClusterHealthResponse
-			err := json.NewDecoder(bytes.NewReader(input.Bytes())).Decode(&out)
+			err := json.NewDecoder(bytes.NewReader(resClusterStats.Bytes())).Decode(&out)
 			if err != nil {
 				b.Error(err)
 			}
@@ -78,10 +170,10 @@ func BenchmarkClusterStats(b *testing.B) {
 		}
 	})
 
-	b.Run("gjson", func(b *testing.B) {
+	b.Run("Cluster - gjson", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			var out []gjson.Result
-			out = gjson.GetManyBytes(input.Bytes(), "cluster_name", "status", "indices.count", "indices.docs.count")
+			out = gjson.GetManyBytes(resClusterStats.Bytes(), "cluster_name", "status", "indices.count", "indices.docs.count")
 			if len(out[0].String()) < 3 {
 				b.Errorf("Unexpected len(%s)=%d", out[0], len(out[0].String()))
 			}
diff --git a/_examples/encoding/easyjson.go b/_examples/encoding/easyjson.go
index 7e72e55065..02767bbe93 100644
--- a/_examples/encoding/easyjson.go
+++ b/_examples/encoding/easyjson.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
 import (
@@ -9,12 +26,12 @@ import (
 	"strings"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 	"github.com/fatih/color"
 	"github.com/mailru/easyjson"
 
-	"github.com/elastic/go-elasticsearch/_examples/encoding/model"
+	"github.com/elastic/go-elasticsearch/v7/_examples/encoding/model"
 )
 
 var (
diff --git a/_examples/encoding/gjson.go b/_examples/encoding/gjson.go
index 3fe0a29f97..a0f0953d67 100644
--- a/_examples/encoding/gjson.go
+++ b/_examples/encoding/gjson.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
 import (
@@ -7,7 +24,7 @@ import (
 	"log"
 	"strings"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 	"github.com/fatih/color"
 	"github.com/tidwall/gjson"
 )
diff --git a/_examples/encoding/go.mod b/_examples/encoding/go.mod
index cfe35921b1..aea796f858 100644
--- a/_examples/encoding/go.mod
+++ b/_examples/encoding/go.mod
@@ -1,18 +1,15 @@
-module github.com/elastic/go-elasticsearch/_examples/encoding
+module github.com/elastic/go-elasticsearch/v7/_examples/encoding
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../..
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
 require (
-	github.com/elastic/go-elasticsearch v0.0.1-0.20190316081522-60ea51fd3784
-
+	github.com/elastic/go-elasticsearch/v7 v7.0.0-20190407092644-3fb2a278216b
 	github.com/fatih/color v1.7.0
-
-	github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe
+	github.com/mailru/easyjson v0.7.7
 	github.com/mattn/go-colorable v0.1.1 // indirect
 	github.com/mattn/go-isatty v0.0.7 // indirect
-
 	github.com/tidwall/gjson v1.2.1
 	github.com/tidwall/match v1.0.1 // indirect
 	github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 // indirect
diff --git a/_examples/encoding/jsonreader.go b/_examples/encoding/jsonreader.go
new file mode 100644
index 0000000000..e4d5d3f978
--- /dev/null
+++ b/_examples/encoding/jsonreader.go
@@ -0,0 +1,72 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+	"log"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+func init() {
+	log.SetFlags(0)
+}
+
+func main() {
+	var (
+		res *esapi.Response
+		err error
+	)
+
+	es, err := elasticsearch.NewDefaultClient()
+	if err != nil {
+		log.Fatalf("Error creating the client: %s", err)
+	}
+
+	doc := struct {
+		Title string `json:"title"`
+	}{Title: "Test"}
+
+	res, err = es.Index("test", esutil.NewJSONReader(&doc), es.Index.WithRefresh("true"))
+	if err != nil {
+		log.Fatalf("Error getting response: %s", err)
+	}
+
+	log.Println(res)
+
+	query := map[string]interface{}{
+		"query": map[string]interface{}{
+			"match": map[string]interface{}{
+				"title": "test",
+			},
+		},
+	}
+
+	res, err = es.Search(
+		es.Search.WithIndex("test"),
+		es.Search.WithBody(esutil.NewJSONReader(&query)),
+		es.Search.WithPretty(),
+	)
+	if err != nil {
+		log.Fatalf("Error getting response: %s", err)
+	}
+
+	log.Println(res)
+}
diff --git a/_examples/encoding/model/model.go b/_examples/encoding/model/model.go
index c3612807bb..b6b9959e6b 100644
--- a/_examples/encoding/model/model.go
+++ b/_examples/encoding/model/model.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 //go:generate easyjson -all -snake_case $GOFILE
 
 package model
diff --git a/_examples/encoding/model/response.go b/_examples/encoding/model/response.go
index 316dbdca14..0c08804918 100644
--- a/_examples/encoding/model/response.go
+++ b/_examples/encoding/model/response.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 //go:generate easyjson -all -snake_case $GOFILE
 
 package model
diff --git a/_examples/extension/Makefile b/_examples/extension/Makefile
new file mode 100644
index 0000000000..f970ebe60d
--- /dev/null
+++ b/_examples/extension/Makefile
@@ -0,0 +1,8 @@
+GO_TEST_CMD = $(if $(shell which richgo),richgo test,go test)
+
+test:  ## Run tests
+	go run main.go
+
+setup:
+
+.PHONY: test setup
diff --git a/_examples/extension/README.md b/_examples/extension/README.md
new file mode 100644
index 0000000000..c2b99baf70
--- /dev/null
+++ b/_examples/extension/README.md
@@ -0,0 +1,17 @@
+# Example: Extending the Client
+
+This example demonstrates how to extend the client, in order to call custom APIs, for example added by a [plugin](https://github.com/elastic/elasticsearch/blob/master/plugins/examples/rest-handler/src/main/java/org/elasticsearch/example/resthandler/ExampleCatAction.java).
+
+The [`main.go`](main.go) example defines a custom type, which embeds the regular Elasticsearch client, and adds a `Custom` namespace with an `Example()` method.
+
+To run the example:
+
+```bash
+go run main.go
+
+#    GET http://localhost:9209/_cat/health 200 OK 25ms
+#        « 1555252476 14:34:36 go-elasticsearch green 1 1 0 0 0 0 0 0 - 100.0%
+#
+#    GET http://localhost:9209/_cat/example 200 OK 0s
+#        « Hello from Cat Example action
+```
diff --git a/_examples/extension/main.go b/_examples/extension/main.go
new file mode 100644
index 0000000000..55d66b27ca
--- /dev/null
+++ b/_examples/extension/main.go
@@ -0,0 +1,115 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+// This examples demonstrates how extend the API of the client by embedding it inside a custom type.
+
+package main
+
+import (
+	"io"
+	"log"
+	"net"
+	"net/http"
+	"net/http/httputil"
+	"net/url"
+	"os"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+const port = "9209"
+
+// ExtendedClient allows to call regular and custom APIs.
+//
+type ExtendedClient struct {
+	*elasticsearch.Client
+	Custom *ExtendedAPI
+}
+
+// ExtendedAPI contains custom APIs.
+//
+type ExtendedAPI struct {
+	*elasticsearch.Client
+}
+
+// Example calls a custom REST API, "/_cat/example".
+//
+func (c *ExtendedAPI) Example() (*esapi.Response, error) {
+	req, _ := http.NewRequest("GET", "/_cat/example", nil) // errcheck exclude
+
+	res, err := c.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	return &esapi.Response{StatusCode: res.StatusCode, Body: res.Body, Header: res.Header}, nil
+}
+
+func main() {
+	log.SetFlags(0)
+
+	started := make(chan bool)
+
+	// --> Start the proxy server
+	//
+	go startServer(started)
+
+	esclient, err := elasticsearch.NewClient(elasticsearch.Config{
+		Addresses: []string{"http://localhost:" + port},
+		Logger:    &estransport.ColorLogger{Output: os.Stdout, EnableRequestBody: true, EnableResponseBody: true},
+	})
+	if err != nil {
+		log.Fatalf("Error creating the client: %s", err)
+	}
+
+	es := ExtendedClient{Client: esclient, Custom: &ExtendedAPI{esclient}}
+	<-started
+
+	// --> Call a regular Elasticsearch API
+	//
+	es.Cat.Health()
+
+	// --> Call a custom API
+	//
+	es.Custom.Example()
+}
+
+func startServer(started chan<- bool) {
+	proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: "http", Host: "localhost:9200"})
+
+	// Respond with custom content on "GET /_cat/example", proxy to Elasticsearch for other requests
+	//
+	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "GET" && r.URL.Path == "/_cat/example" {
+			io.WriteString(w, "Hello from Cat Example action")
+			return
+		}
+		proxy.ServeHTTP(w, r)
+	})
+
+	ln, err := net.Listen("tcp", "localhost:"+port)
+	if err != nil {
+		log.Fatalf("Unable to start server: %s", err)
+	}
+
+	go http.Serve(ln, nil)
+	started <- true
+}
diff --git a/_examples/fasthttp/.gitignore b/_examples/fasthttp/.gitignore
old mode 100755
new mode 100644
diff --git a/_examples/fasthttp/Makefile b/_examples/fasthttp/Makefile
old mode 100755
new mode 100644
index 579cc74aff..f1ad886fde
--- a/_examples/fasthttp/Makefile
+++ b/_examples/fasthttp/Makefile
@@ -6,4 +6,8 @@ test:  ## Run tests
 bench:  ## Run benchmarks
 	$(GO_TEST_CMD) -run=none -bench=. -benchmem -benchtime=10s -v fasthttp_benchmark_test.go
 
-.PHONY: test bench
+setup:
+	@go mod tidy
+	@go mod download
+
+.PHONY: test bench setup
diff --git a/_examples/fasthttp/README.md b/_examples/fasthttp/README.md
old mode 100755
new mode 100644
index 9dd59a92c0..df093a6c88
--- a/_examples/fasthttp/README.md
+++ b/_examples/fasthttp/README.md
@@ -9,11 +9,11 @@ request and response object between `net/http` and `fasthttp`.
 To run the example:
 
     go run cmd/main.go
-    # 1000 requests in 1.15 (870.2 req/s) | min: 785.292µs / max: 10.553253ms / mean: 1.052083ms
+    # 1000 requests in 1.07 (933.4 req/s) | min: 749.961µs / max: 10.003318ms / mean: 1.013992ms
 
 To run the benchmarks:
 
     make bench
 
-    BenchmarkHTTPClient/Info()-4              2000     8721355 ns/op     16279 B/op      131 allocs/op
-    BenchmarkFastHTTPClient/Info()-4         10000     1182717 ns/op      3075 B/op       39 allocs/op
+    BenchmarkHTTPClient/Info()-4         	    1591	   7139770 ns/op	   16725 B/op	     132 allocs/op
+    BenchmarkFastHTTPClient/Info()-4     	   10000	   1315049 ns/op	    2255 B/op	      24 allocs/op
diff --git a/_examples/fasthttp/cmd/main.go b/_examples/fasthttp/cmd/main.go
old mode 100755
new mode 100644
index 131da81250..7353403f6b
--- a/_examples/fasthttp/cmd/main.go
+++ b/_examples/fasthttp/cmd/main.go
@@ -1,14 +1,33 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
 import (
+	"context"
 	"log"
 	"os"
 	"sort"
 	"strconv"
+	"strings"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/_examples/fasthttp"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/_examples/fasthttp"
 )
 
 var (
@@ -38,6 +57,31 @@ func main() {
 		log.Fatalf("Error creating the client: %s", err)
 	}
 
+	// Test sending the body as POST
+	//
+	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
+	defer cancel()
+
+	go func() {
+		es.Info()
+		if _, err := es.Search(
+			es.Search.WithBody(strings.NewReader(`{"query":{"match":{"title":"foo"}}}`)),
+			es.Search.WithPretty(),
+		); err != nil {
+			log.Fatalf("Error getting response: %s", err)
+		}
+		cancel()
+	}()
+
+	select {
+	case <-ctx.Done():
+		if ctx.Err() != context.Canceled {
+			log.Fatalf("Timeout: %s", ctx.Err())
+		}
+	}
+
+	// Run benchmark
+	//
 	t := time.Now()
 	for i := 0; i < count; i++ {
 		t0 := time.Now()
diff --git a/_examples/fasthttp/fasthttp.go b/_examples/fasthttp/fasthttp.go
old mode 100755
new mode 100644
index 5f8744efbe..bfe3b9130a
--- a/_examples/fasthttp/fasthttp.go
+++ b/_examples/fasthttp/fasthttp.go
@@ -1,10 +1,26 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package fasthttp
 
 import (
-	"bytes"
-	"io"
 	"io/ioutil"
 	"net/http"
+	"strings"
 
 	"github.com/valyala/fasthttp"
 )
@@ -18,8 +34,13 @@ type Transport struct{}
 //
 func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
 	freq := fasthttp.AcquireRequest()
+	defer fasthttp.ReleaseRequest(freq)
+
 	fres := fasthttp.AcquireResponse()
+	defer fasthttp.ReleaseResponse(fres)
+
 	t.copyRequest(freq, req)
+
 	err := fasthttp.Do(freq, fres)
 	if err != nil {
 		return nil, err
@@ -31,10 +52,12 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
 	return res, nil
 }
 
-// copyRequest converts http.Request to fasthttp.Request
+// copyRequest converts a http.Request to fasthttp.Request
 //
 func (t *Transport) copyRequest(dst *fasthttp.Request, src *http.Request) *fasthttp.Request {
-	dst.Reset()
+	if src.Method == "GET" && src.Body != nil {
+		src.Method = "POST"
+	}
 
 	dst.SetHost(src.Host)
 	dst.SetRequestURI(src.URL.String())
@@ -49,16 +72,13 @@ func (t *Transport) copyRequest(dst *fasthttp.Request, src *http.Request) *fasth
 	}
 
 	if src.Body != nil {
-		var b bytes.Buffer
-		io.Copy(&b, src.Body)
-
-		dst.SetBody(b.Bytes())
+		dst.SetBodyStream(src.Body, -1)
 	}
 
 	return dst
 }
 
-// copyResponse converts http.Response to fasthttp.Response
+// copyResponse converts a http.Response to fasthttp.Response
 //
 func (t *Transport) copyResponse(dst *http.Response, src *fasthttp.Response) *http.Response {
 	dst.StatusCode = src.StatusCode()
@@ -67,9 +87,9 @@ func (t *Transport) copyResponse(dst *http.Response, src *fasthttp.Response) *ht
 		dst.Header.Set(string(k), string(v))
 	})
 
-	if src.Body != nil {
-		dst.Body = ioutil.NopCloser(bytes.NewReader(src.Body()))
-	}
+	// Cast to a string to make a copy seeing as src.Body() won't
+	// be valid after the response is released back to the pool (fasthttp.ReleaseResponse).
+	dst.Body = ioutil.NopCloser(strings.NewReader(string(src.Body())))
 
 	return dst
 }
diff --git a/_examples/fasthttp/fasthttp_benchmark_test.go b/_examples/fasthttp/fasthttp_benchmark_test.go
old mode 100755
new mode 100644
index 5be123fe40..8fbcc00cca
--- a/_examples/fasthttp/fasthttp_benchmark_test.go
+++ b/_examples/fasthttp/fasthttp_benchmark_test.go
@@ -1,10 +1,27 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package fasthttp_test
 
 import (
 	"testing"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/_examples/fasthttp"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/_examples/fasthttp"
 )
 
 func BenchmarkHTTPClient(b *testing.B) {
diff --git a/_examples/fasthttp/go.mod b/_examples/fasthttp/go.mod
index e7106dacf9..85d22367aa 100644
--- a/_examples/fasthttp/go.mod
+++ b/_examples/fasthttp/go.mod
@@ -1,10 +1,12 @@
-module github.com/elastic/go-elasticsearch/_examples/fasthttp
+module github.com/elastic/go-elasticsearch/v7/_examples/fasthttp
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../..
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
 require (
-	github.com/elastic/go-elasticsearch master
-	github.com/valyala/fasthttp v1.1.0
+	github.com/andybalholm/brotli v1.0.3 // indirect
+	github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210608143310-9747f0e42f35
+	github.com/klauspost/compress v1.13.1 // indirect
+	github.com/valyala/fasthttp v1.27.0
 )
diff --git a/_examples/instrumentation/Dockerfile b/_examples/instrumentation/Dockerfile
index 0e6ccde2bc..948475d1ce 100644
--- a/_examples/instrumentation/Dockerfile
+++ b/_examples/instrumentation/Dockerfile
@@ -1,13 +1,13 @@
 # $ docker build --tag elastic/go-elasticsearch-demo-instrumentation .
 # $ docker run -it --network instrumentation_elasticstack --rm elastic/go-elasticsearch-demo-instrumentation
 #
-FROM golang:1.11-alpine
+FROM golang:1-alpine
 
 RUN apk add --no-cache --quiet gcc g++ ca-certificates make curl git jq
 
 WORKDIR /go-elasticsearch-demo-instrumentation
 
-COPY ./go.mod ./
+COPY go.mod .
 RUN go mod download
 
 ENV TERM xterm-256color
@@ -20,6 +20,6 @@ ENV ELASTIC_APM_METRICS_INTERVAL=5s
 ENV ELASTIC_APM_LOG_FILE=stderr
 ENV ELASTIC_APM_LOG_LEVEL=debug
 
-COPY ./apmelasticsearch.go ./opencensus.go ./
+COPY apmelasticsearch.go opencensus.go ./
 
 CMD go run apmelasticsearch.go
diff --git a/_examples/instrumentation/Makefile b/_examples/instrumentation/Makefile
index 0e16dc3ae1..9081ad33d5 100644
--- a/_examples/instrumentation/Makefile
+++ b/_examples/instrumentation/Makefile
@@ -1,5 +1,11 @@
 test:
+	go build -o /dev/null expvar.go
 	go build -o /dev/null opencensus.go
 	go build -o /dev/null apmelasticsearch.go
 
-.PHONY: test
+setup:
+	@go mod tidy
+	@go mod download
+
+
+.PHONY: test setup
diff --git a/_examples/instrumentation/README.md b/_examples/instrumentation/README.md
index bc03f62940..4cc31bd4a8 100644
--- a/_examples/instrumentation/README.md
+++ b/_examples/instrumentation/README.md
@@ -17,3 +17,7 @@ The [**`apmelasticsearch.go`**](./apmelasticsearch.go) example demonstrates inst
 Run the example interactively with Docker and inspect the UI in <a href="http://localhost:5601/app/apm#/go-elasticsearch-demo-instrumentation/transactions?_g=(time:(from:now-15m,to:now))">Kibana</a>:
 
     docker-compose --file elasticstack.yml up --build
+
+To destroy the Docker assets for the example, run:
+
+    docker-compose --file elasticstack.yml down --remove-orphans --volumes
diff --git a/_examples/instrumentation/apmelasticsearch.go b/_examples/instrumentation/apmelasticsearch.go
index 942dab89be..dc198d4a47 100644
--- a/_examples/instrumentation/apmelasticsearch.go
+++ b/_examples/instrumentation/apmelasticsearch.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
 import (
@@ -18,7 +35,7 @@ import (
 	"github.com/fatih/color"
 	"golang.org/x/crypto/ssh/terminal"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
 	"go.elastic.co/apm"
 	"go.elastic.co/apm/module/apmelasticsearch"
diff --git a/_examples/instrumentation/elasticstack.yml b/_examples/instrumentation/elasticstack.yml
index 16fd9f4e8d..a252d99634 100644
--- a/_examples/instrumentation/elasticstack.yml
+++ b/_examples/instrumentation/elasticstack.yml
@@ -16,7 +16,7 @@ services:
 
   # --- Elasticsearch ---------------------------------------------------------
   elasticsearch:
-    image: docker.elastic.co/elasticsearch/elasticsearch:${VERSION:-7.0.0-beta1}
+    image: docker.elastic.co/elasticsearch/elasticsearch:${VERSION:-7.0.0}
     container_name: elasticsearch
     volumes:
       - es_data:/usr/share/elasticsearch/data:delegated
@@ -39,7 +39,7 @@ services:
 
   # --- Kibana ----------------------------------------------------------------
   kibana:
-    image: docker.elastic.co/kibana/kibana:${VERSION:-7.0.0-beta1}
+    image: docker.elastic.co/kibana/kibana:${VERSION:-7.0.0}
     container_name: kibana
     networks: ['elasticstack']
     environment:
@@ -52,7 +52,7 @@ services:
 
   # --- APM Server ------------------------------------------------------------
   apm-server:
-    image: docker.elastic.co/apm/apm-server:${VERSION:-7.0.0-beta1}
+    image: docker.elastic.co/apm/apm-server:${VERSION:-7.0.0}
     container_name: apm_server
     networks: ['elasticstack']
     command: >
diff --git a/_examples/instrumentation/expvar.go b/_examples/instrumentation/expvar.go
new file mode 100644
index 0000000000..703c782310
--- /dev/null
+++ b/_examples/instrumentation/expvar.go
@@ -0,0 +1,144 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+	"expvar"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/signal"
+	"runtime"
+	"strings"
+	"syscall"
+	"time"
+
+	// Import the "expvar" and "pprof" package >>>>>>>>>>
+	"net/http"
+	_ "net/http/pprof"
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	"golang.org/x/crypto/ssh/terminal"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+var (
+	tWidth, _, _ = terminal.GetSize(int(os.Stdout.Fd()))
+)
+
+func init() {
+	runtime.SetMutexProfileFraction(10)
+}
+
+func main() {
+	log.SetFlags(0)
+
+	ticker := time.NewTicker(time.Second)
+	defer ticker.Stop()
+
+	aborted := make(chan os.Signal)
+	signal.Notify(aborted, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
+
+	go func() {
+		<-aborted
+
+		log.Println("\nDone!\n")
+		os.Exit(0)
+	}()
+
+	log.Println(strings.Repeat("─", tWidth))
+	log.Println("Open <http://localhost:6060/debug/vars> to see all exported variables.")
+	log.Println(strings.Repeat("─", tWidth))
+
+	// Start the debug server >>>>>>>>>>>>>>>>>>>>>>>>>>>
+	go func() { log.Fatalln(http.ListenAndServe("localhost:6060", nil)) }()
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	for i := 1; i <= 2; i++ {
+		go func(i int) {
+			log.Printf("==> Starting server on <localhost:1000%d>", i)
+			if err := http.ListenAndServe(
+				fmt.Sprintf("localhost:1000%d", i),
+				http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "OK\n") }),
+			); err != nil && err != http.ErrServerClosed {
+				log.Fatalf("Unable to start server: %s", err)
+			}
+		}(i)
+	}
+
+	es, err := elasticsearch.NewClient(
+		elasticsearch.Config{
+			Addresses: []string{
+				"http://localhost:10001",
+				"http://localhost:10002",
+				"http://localhost:10003",
+			},
+
+			Logger:            &estransport.ColorLogger{Output: os.Stdout},
+			DisableRetry:      true,
+			EnableDebugLogger: true,
+
+			// Enable metric collection >>>>>>>>>>>>>>>>>>>>>>>>>
+			EnableMetrics: true,
+			// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+		})
+	if err != nil {
+		log.Fatal("ERROR: %s", err)
+	}
+
+	// Publish client metrics to expvar >>>>>>>>>>>>>>>>>
+	expvar.Publish("go-elasticsearch", expvar.Func(func() interface{} { m, _ := es.Metrics(); return m }))
+	// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+	for {
+		select {
+		case t := <-ticker.C:
+
+			go func() {
+				if res, _ := es.Info(); res != nil {
+					res.Body.Close()
+				}
+			}()
+
+			go func() {
+				if res, _ := es.Cluster.Health(); res != nil {
+					res.Body.Close()
+				}
+			}()
+
+			if t.Second()%5 == 0 {
+				m, err := es.Metrics()
+				if err != nil {
+					log.Printf("\x1b[31;1mUnable to get metrics: %s\x1b[0m", err)
+					continue
+				}
+				log.Println("███", fmt.Sprintf("\x1b[1m%s\x1b[0m", "Metrics"), strings.Repeat("█", tWidth-12))
+				log.Printf(
+					""+
+						"    \x1b[2mRequests:   \x1b[0m %d\n"+
+						"    \x1b[2mFailures:   \x1b[0m %d\n"+
+						"    \x1b[2mConnections:\x1b[0m %s",
+					m.Requests, m.Failures, m.Connections)
+				log.Println(strings.Repeat("─", tWidth))
+			}
+		}
+	}
+}
diff --git a/_examples/instrumentation/go.mod b/_examples/instrumentation/go.mod
index fb0e60f4b1..68dae7c242 100644
--- a/_examples/instrumentation/go.mod
+++ b/_examples/instrumentation/go.mod
@@ -1,18 +1,16 @@
-module github.com/elastic/go-elasticsearch/_examples/instrumentation/opencensus
+module github.com/elastic/go-elasticsearch/v7/_examples/instrumentation/opencensus
 
 go 1.11
 
-require (
-	github.com/elastic/go-elasticsearch master
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
+require (
+	github.com/elastic/go-elasticsearch/v7 v7.0.0-20190407092644-3fb2a278216b
 	github.com/fatih/color v1.7.0
 	github.com/mattn/go-colorable v0.1.0 // indirect
 	github.com/mattn/go-isatty v0.0.4 // indirect
-
-	go.elastic.co/apm v1.2.1-0.20190212105052-525c5c425aa9
-	go.elastic.co/apm/module/apmelasticsearch v1.2.1-0.20190212105052-525c5c425aa9
-
+	go.elastic.co/apm v1.5.0
+	go.elastic.co/apm/module/apmelasticsearch v1.5.0
 	go.opencensus.io v0.19.0
-
-	golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67
+	golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
 )
diff --git a/_examples/instrumentation/opencensus.go b/_examples/instrumentation/opencensus.go
index 5c837cf1df..b38cb796b7 100644
--- a/_examples/instrumentation/opencensus.go
+++ b/_examples/instrumentation/opencensus.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
 import (
@@ -14,7 +31,7 @@ import (
 	"github.com/fatih/color"
 	"golang.org/x/crypto/ssh/terminal"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
 	"go.opencensus.io/plugin/ochttp"
 	"go.opencensus.io/stats/view"
diff --git a/_examples/logging/Makefile b/_examples/logging/Makefile
index 1eda8beb7a..360f8d2e7b 100644
--- a/_examples/logging/Makefile
+++ b/_examples/logging/Makefile
@@ -4,4 +4,8 @@ test:  ## Run tests
 	go run default.go
 	go run custom.go
 
-.PHONY: test
+setup:
+	@go mod download
+	@go mod download github.com/rs/zerolog
+
+.PHONY: test setup
diff --git a/_examples/logging/custom.go b/_examples/logging/custom.go
index 3f5820e557..e1f15f3d3d 100644
--- a/_examples/logging/custom.go
+++ b/_examples/logging/custom.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 // This examples demonstrates how to implement the "estransport.Logger" interface with a custom type,
@@ -15,7 +32,7 @@ import (
 
 	"github.com/rs/zerolog"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 )
 
 // CustomLogger implements the estransport.Logger interface.
diff --git a/_examples/logging/default.go b/_examples/logging/default.go
index cfd7d646ef..e93b38e16a 100644
--- a/_examples/logging/default.go
+++ b/_examples/logging/default.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 // This collection of examples demonstrates how to configure the default logger of the client.
@@ -14,8 +31,8 @@ import (
 	"os"
 	"strings"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
 func main() {
diff --git a/_examples/logging/go.mod b/_examples/logging/go.mod
index 184501b9fe..fce55e5ada 100644
--- a/_examples/logging/go.mod
+++ b/_examples/logging/go.mod
@@ -1,11 +1,11 @@
-module github.com/elastic/go-elasticsearch/_examples/logging
+module github.com/elastic/go-elasticsearch/v7/_examples/logging
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../..
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
 require (
-	github.com/elastic/go-elasticsearch master
+	github.com/elastic/go-elasticsearch/v7 v7.0.0-20190407092644-3fb2a278216b
 
 	github.com/rs/zerolog v1.11.0
 )
diff --git a/_examples/main.go b/_examples/main.go
old mode 100755
new mode 100644
index 35e71df648..5535f78417
--- a/_examples/main.go
+++ b/_examples/main.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 // This example demonstrates a basic usage of the Elasticsearch Go client.
@@ -8,6 +25,7 @@
 package main
 
 import (
+	"bytes"
 	"context"
 	"encoding/json"
 	"log"
@@ -15,8 +33,8 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 func main() {
@@ -63,11 +81,17 @@ func main() {
 		go func(i int, title string) {
 			defer wg.Done()
 
-			// Set up the request object directly.
+			// Build the request body.
+			var b strings.Builder
+			b.WriteString(`{"title" : "`)
+			b.WriteString(title)
+			b.WriteString(`"}`)
+
+			// Set up the request object.
 			req := esapi.IndexRequest{
 				Index:      "test",
 				DocumentID: strconv.Itoa(i + 1),
-				Body:       strings.NewReader(`{"title" : "` + title + `"}`),
+				Body:       strings.NewReader(b.String()),
 				Refresh:    "true",
 			}
 
@@ -98,23 +122,36 @@ func main() {
 
 	// 3. Search for the indexed documents
 	//
-	// Use the helper methods of the client.
+	// Build the request body.
+	var buf bytes.Buffer
+	query := map[string]interface{}{
+		"query": map[string]interface{}{
+			"match": map[string]interface{}{
+				"title": "test",
+			},
+		},
+	}
+	if err := json.NewEncoder(&buf).Encode(query); err != nil {
+		log.Fatalf("Error encoding query: %s", err)
+	}
+
+	// Perform the search request.
 	res, err = es.Search(
 		es.Search.WithContext(context.Background()),
 		es.Search.WithIndex("test"),
-		es.Search.WithBody(strings.NewReader(`{"query" : { "match" : { "title" : "test" } }}`)),
+		es.Search.WithBody(&buf),
 		es.Search.WithTrackTotalHits(true),
 		es.Search.WithPretty(),
 	)
 	if err != nil {
-		log.Fatalf("ERROR: %s", err)
+		log.Fatalf("Error getting response: %s", err)
 	}
 	defer res.Body.Close()
 
 	if res.IsError() {
 		var e map[string]interface{}
 		if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
-			log.Fatalf("error parsing the response body: %s", err)
+			log.Fatalf("Error parsing the response body: %s", err)
 		} else {
 			// Print the response status and error information.
 			log.Fatalf("[%s] %s: %s",
diff --git a/_examples/security/.env b/_examples/security/.env
new file mode 100644
index 0000000000..2bcf395dd6
--- /dev/null
+++ b/_examples/security/.env
@@ -0,0 +1,4 @@
+COMPOSE_PROJECT_NAME='example'
+
+ELASTIC_VERSION=7.x-SNAPSHOT
+ELASTIC_PASSWORD=elastic
diff --git a/_examples/security/.gitignore b/_examples/security/.gitignore
new file mode 100644
index 0000000000..eaea94840e
--- /dev/null
+++ b/_examples/security/.gitignore
@@ -0,0 +1,4 @@
+go.sum
+
+certificates/
+tmp/
diff --git a/_examples/security/Makefile b/_examples/security/Makefile
new file mode 100644
index 0000000000..4b8ea62710
--- /dev/null
+++ b/_examples/security/Makefile
@@ -0,0 +1,36 @@
+test:
+	@for file in ./*.go; do \
+		echo "go build -o /dev/null $$file"; \
+		go build -o /dev/null $$file; \
+	done;
+
+test-integ:
+	@for file in ./*.go; do \
+		echo "go run $$file"; \
+		go run $$file; \
+	done;
+
+certificates: certificates-clean
+	docker-compose --file certificates-create.yml run --rm create_certificates
+
+cluster:
+	docker-compose --file elasticsearch-cluster.yml up --remove-orphans --detach; echo;
+	@docker-compose --file elasticsearch-cluster.yml ps;
+	@{ \
+		set -e; \
+		until \
+			docker inspect example_elasticsearch_1 > /dev/null 2>&1 && \
+			[[ `docker inspect -f "{{ .State.Health.Status }}" example_elasticsearch_1` == "healthy" ]]; \
+				do printf '-'; sleep 1; \
+		done; echo "> [OK]"; \
+	}
+
+certificates-clean:
+	rm -rf ./certificates
+
+cluster-clean:
+	docker-compose --file elasticsearch-cluster.yml down --volumes
+
+setup:
+
+.PHONY: test test-integ certificates cluster certificates-clean cluster-clean setup
diff --git a/_examples/security/README.md b/_examples/security/README.md
new file mode 100644
index 0000000000..8a1b5c382e
--- /dev/null
+++ b/_examples/security/README.md
@@ -0,0 +1,76 @@
+# Example: Security
+
+This example demonstrates how to use Transport Layer Security (TLS) for
+encrypting and verifying the communication with an Elasticsearch cluster
+by passing a custom certificate authority to the client.
+
+## Creating the certificates for the cluster nodes
+
+Generate the certificates using the
+[`elasticsearch-certutil`](https://www.elastic.co/guide/en/elasticsearch/reference/current/certutil.html)
+tool:
+
+```bash
+make certificates
+```
+
+> See the [_Encrypting communications in an Elasticsearch Docker Container_](https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-tls-docker.html) tutorial for a complete overview.
+
+Start the cluster with full security configuration:
+
+```bash
+make cluster
+```
+
+See the [`elasticsearch-cluster.yml`](elasticsearch-cluster.yml) file for details.
+
+Use `curl` to verify access to the cluster:
+
+```
+curl --cacert certificates/ca/ca.crt https://elastic:elastic@localhost:9200
+```
+
+> NOTE: On Mac OS X, you may need to add the certificate to the Keychain with `security add-trusted-cert -p ssl certificates/ca/ca.crt`. To remove it, run `security remove-trusted-cert certificates/ca/ca.crt`.
+
+
+## Using the client configuration option
+
+To pass the certificate authority (CA) to the client, so it can verify the server certificate,
+use the `elasticsearch.Config.CACert` configuration option:
+
+```go
+// --> Read the certificate from file
+cert, _ := ioutil.ReadFile(*cacert)
+
+es, _ := elasticsearch.NewClient(
+	elasticsearch.Config{
+		// ...
+
+		// --> Pass the certificate to the client
+		CACert: cert,
+	})
+```
+
+Run the full example:
+
+```bash
+go run tls_with_ca.go
+
+# [200 OK] {
+# ...
+```
+
+
+## Manual transport configuration
+
+To configure the transport manually, use the
+`(*http.Transport).TLSClientConfig.RootCAs.AppendCertsFromPEM()` method.
+
+Run the full example:
+
+```bash
+go run tls_configure_ca.go
+
+# [200 OK] {
+# ...
+```
diff --git a/_examples/security/certificates-config.yml b/_examples/security/certificates-config.yml
new file mode 100644
index 0000000000..76e6e8dd46
--- /dev/null
+++ b/_examples/security/certificates-config.yml
@@ -0,0 +1,4 @@
+instances:
+  - name: elasticsearch
+    ip:  [0.0.0.0, 127.0.0.1]
+    dns: ["localhost", "example_elasticsearch_1", "example_elasticsearch_2", "example_elasticsearch_3"]
diff --git a/_examples/security/certificates-create.yml b/_examples/security/certificates-create.yml
new file mode 100644
index 0000000000..363ae92ed8
--- /dev/null
+++ b/_examples/security/certificates-create.yml
@@ -0,0 +1,35 @@
+# Create the certificates for the stack:
+#
+#     docker-compose --file certificates-create.yml run --rm create_certificates
+#
+# See: https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-tls-docker.html
+
+version: "3.7"
+
+services:
+  create_certificates:
+    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION}
+    container_name: certificates_generator
+    user: root
+    working_dir: /usr/share/elasticsearch
+    command: >
+      bash -c '
+        OUTPUT="/certificates/bundle.zip"
+        if [[ -f $$OUTPUT ]]; then
+          echo "Certificates already present in [.$$OUTPUT]"; exit 1;
+        else
+          yum install -y -q -e 0 unzip tree;
+          bin/elasticsearch-certutil cert \
+            --pem \
+            --days 365 \
+            --keep-ca-key \
+            --in config/certificates/certificates-config.yml \
+            --out $$OUTPUT;
+          unzip -q $$OUTPUT -d /certificates;
+          chown -R 1000:0 /certificates; echo;
+          tree /certificates;
+        fi;
+      '
+    volumes:
+      - ./certificates:/certificates
+      - ./certificates-config.yml:/usr/share/elasticsearch/config/certificates/certificates-config.yml
diff --git a/_examples/security/elasticsearch-cluster.yml b/_examples/security/elasticsearch-cluster.yml
new file mode 100644
index 0000000000..45cda288b8
--- /dev/null
+++ b/_examples/security/elasticsearch-cluster.yml
@@ -0,0 +1,44 @@
+# This configuration file will launch Elasticsearch Stack with full TLS configuration and authentication.
+
+version: "3.7"
+
+services:
+  elasticsearch:
+    image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION}
+    volumes:
+      - es-data:/usr/share/elasticsearch/data
+      - ./certificates:/usr/share/elasticsearch/config/certificates/
+    networks:
+      - elasticstack
+    ports:
+      - 9200:9200
+    environment:
+      - node.name=example_elasticsearch_1
+      - cluster.name=golang-example-security
+      - cluster.initial_master_nodes=example_elasticsearch_1
+      - discovery.seed_hosts=example_elasticsearch_1
+      - bootstrap.memory_lock=true
+      - network.host=example_elasticsearch_1,_local_
+      - network.publish_host=example_elasticsearch_1
+      - ES_JAVA_OPTS=-Xms1G -Xmx1G -Des.transport.cname_in_publish_address=true
+      # Security & TLS
+      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
+      - xpack.security.enabled=true
+      - xpack.security.http.ssl.enabled=true
+      - xpack.security.http.ssl.key=/usr/share/elasticsearch/config/certificates/elasticsearch/testnode.key
+      - xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/certificates/elasticsearch/testnode.crt
+      - xpack.security.http.ssl.certificate_authorities=/usr/share/elasticsearch/config/certificates/ca/ca.crt
+      - xpack.security.transport.ssl.enabled=true
+      - xpack.security.transport.ssl.verification_mode=certificate
+      - xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/certificates/elasticsearch/testnode.key
+      - xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/certificates/elasticsearch/testnode.crt
+      - xpack.security.transport.ssl.certificate_authorities=/usr/share/elasticsearch/config/certificates/ca/ca.crt
+    ulimits: { nofile: { soft: 65535, hard: 65535 }, memlock: -1 }
+    healthcheck:
+      test: curl --cacert /usr/share/elasticsearch/config/certificates/ca/ca.crt --max-time 120 --retry 120 --retry-delay 1 --show-error --silent https://elastic:${ELASTIC_PASSWORD}@localhost:9200
+
+networks:
+  elasticstack: { labels: { elasticstack.description: "Network for the Elastic Stack" }}
+
+volumes:
+  es-data: { labels: { elasticstack.description: "Elasticsearch data" }}
diff --git a/_examples/security/go.mod b/_examples/security/go.mod
new file mode 100644
index 0000000000..21d641f8bb
--- /dev/null
+++ b/_examples/security/go.mod
@@ -0,0 +1,7 @@
+module github.com/elastic/go-elasticsearch/v7/_examples/security
+
+go 1.11
+
+replace github.com/elastic/go-elasticsearch/v7 => ../..
+
+require github.com/elastic/go-elasticsearch/v7 v7.5.1-0.20210608143310-9747f0e42f35
diff --git a/_examples/security/tls_configure_ca.go b/_examples/security/tls_configure_ca.go
new file mode 100644
index 0000000000..bce995fc39
--- /dev/null
+++ b/_examples/security/tls_configure_ca.go
@@ -0,0 +1,87 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+package main
+
+import (
+	"crypto/x509"
+	"flag"
+	"io/ioutil"
+	"log"
+	"net/http"
+
+	"github.com/elastic/go-elasticsearch/v7"
+)
+
+func main() {
+	log.SetFlags(0)
+
+	var (
+		err error
+
+		// --> Configure the path to the certificate authority and the password
+		//
+		cacert   = flag.String("cacert", "certificates/ca/ca.crt", "Path to the file with certificate authority")
+		password = flag.String("password", "elastic", "Elasticsearch password")
+	)
+	flag.Parse()
+
+	ca, err := ioutil.ReadFile(*cacert)
+	if err != nil {
+		log.Fatalf("ERROR: Unable to read CA from %q: %s", *cacert, err)
+	}
+
+	// --> Clone the default HTTP transport
+	//
+	tp := http.DefaultTransport.(*http.Transport).Clone()
+
+	// --> Initialize the set of root certificate authorities
+	//
+	if tp.TLSClientConfig.RootCAs, err = x509.SystemCertPool(); err != nil {
+		log.Fatalf("ERROR: Problem adding system CA: %s", err)
+	}
+
+	// --> Add the custom certificate authority
+	//
+	if ok := tp.TLSClientConfig.RootCAs.AppendCertsFromPEM(ca); !ok {
+		log.Fatalf("ERROR: Problem adding CA from file %q", *cacert)
+	}
+
+	es, err := elasticsearch.NewClient(
+		elasticsearch.Config{
+			Addresses: []string{"https://localhost:9200"},
+			Username:  "elastic",
+			Password:  *password,
+
+			// --> Pass the transport to the client
+			//
+			Transport: tp,
+		},
+	)
+	if err != nil {
+		log.Fatalf("ERROR: Unable to create client: %s", err)
+	}
+
+	res, err := es.Info()
+	if err != nil {
+		log.Fatalf("ERROR: Unable to get response: %s", err)
+	}
+
+	log.Println(res)
+}
diff --git a/_examples/security/tls_with_ca.go b/_examples/security/tls_with_ca.go
new file mode 100644
index 0000000000..f04647df98
--- /dev/null
+++ b/_examples/security/tls_with_ca.go
@@ -0,0 +1,70 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build ignore
+
+package main
+
+import (
+	"flag"
+	"io/ioutil"
+	"log"
+
+	"github.com/elastic/go-elasticsearch/v7"
+)
+
+func main() {
+	log.SetFlags(0)
+
+	var (
+		err error
+
+		// --> Configure the path to the certificate authority and the password
+		//
+		cacert   = flag.String("cacert", "certificates/ca/ca.crt", "Path to the file with certificate authority")
+		password = flag.String("password", "elastic", "Elasticsearch password")
+	)
+	flag.Parse()
+
+	// --> Read the certificate from file
+	//
+	cert, err := ioutil.ReadFile(*cacert)
+	if err != nil {
+		log.Fatalf("ERROR: Unable to read CA from %q: %s", *cacert, err)
+	}
+
+	es, err := elasticsearch.NewClient(
+		elasticsearch.Config{
+			Addresses: []string{"https://localhost:9200"},
+			Username:  "elastic",
+			Password:  *password,
+
+			// --> Pass the certificate to the client
+			//
+			CACert: cert,
+		})
+	if err != nil {
+		log.Fatalf("ERROR: Unable to create client: %s", err)
+	}
+
+	res, err := es.Info()
+	if err != nil {
+		log.Fatalf("ERROR: Unable to get response: %s", err)
+	}
+
+	log.Println(res)
+}
diff --git a/_examples/xkcdsearch/.dockerignore b/_examples/xkcdsearch/.dockerignore
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/.gitignore b/_examples/xkcdsearch/.gitignore
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/Dockerfile b/_examples/xkcdsearch/Dockerfile
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/Makefile b/_examples/xkcdsearch/Makefile
old mode 100755
new mode 100644
index 05f38b4be7..cd71afd4f3
--- a/_examples/xkcdsearch/Makefile
+++ b/_examples/xkcdsearch/Makefile
@@ -3,4 +3,8 @@ GO_TEST_CMD = $(if $(shell which richgo),richgo test,go test)
 test:  ## Run tests
 	$(GO_TEST_CMD) -v ./...
 
-.PHONY: test
+setup:
+	@go mod tidy
+	@go mod download
+
+.PHONY: test setup
diff --git a/_examples/xkcdsearch/README.md b/_examples/xkcdsearch/README.md
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/cmd/xkcd/commands/index.go b/_examples/xkcdsearch/cmd/xkcd/commands/index.go
old mode 100755
new mode 100644
index c8024446c8..5ad697c8f6
--- a/_examples/xkcdsearch/cmd/xkcd/commands/index.go
+++ b/_examples/xkcdsearch/cmd/xkcd/commands/index.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package commands
 
 import (
@@ -14,9 +31,9 @@ import (
 	"github.com/rs/zerolog"
 	"github.com/spf13/cobra"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
-	"github.com/elastic/go-elasticsearch/_examples/xkcdsearch"
+	"github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch"
 )
 
 var (
diff --git a/_examples/xkcdsearch/cmd/xkcd/commands/root.go b/_examples/xkcdsearch/cmd/xkcd/commands/root.go
old mode 100755
new mode 100644
index 464ef8f01d..919843b193
--- a/_examples/xkcdsearch/cmd/xkcd/commands/root.go
+++ b/_examples/xkcdsearch/cmd/xkcd/commands/root.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package commands
 
 import (
diff --git a/_examples/xkcdsearch/cmd/xkcd/commands/search.go b/_examples/xkcdsearch/cmd/xkcd/commands/search.go
old mode 100755
new mode 100644
index 64897334c7..b718cbd294
--- a/_examples/xkcdsearch/cmd/xkcd/commands/search.go
+++ b/_examples/xkcdsearch/cmd/xkcd/commands/search.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package commands
 
 import (
@@ -9,9 +26,9 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
-	"github.com/elastic/go-elasticsearch/_examples/xkcdsearch"
+	"github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch"
 )
 
 func init() {
diff --git a/_examples/xkcdsearch/cmd/xkcd/commands/server.go b/_examples/xkcdsearch/cmd/xkcd/commands/server.go
old mode 100755
new mode 100644
index 9efa0a72bf..abb4255dea
--- a/_examples/xkcdsearch/cmd/xkcd/commands/server.go
+++ b/_examples/xkcdsearch/cmd/xkcd/commands/server.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package commands
 
 import (
@@ -7,9 +24,9 @@ import (
 	"github.com/rs/zerolog"
 	"github.com/spf13/cobra"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
-	"github.com/elastic/go-elasticsearch/_examples/xkcdsearch"
+	"github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch"
 )
 
 var (
diff --git a/_examples/xkcdsearch/cmd/xkcd/main.go b/_examples/xkcdsearch/cmd/xkcd/main.go
old mode 100755
new mode 100644
index 430bcb5679..9cd8545537
--- a/_examples/xkcdsearch/cmd/xkcd/main.go
+++ b/_examples/xkcdsearch/cmd/xkcd/main.go
@@ -1,6 +1,23 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package main
 
-import "github.com/elastic/go-elasticsearch/_examples/xkcdsearch/cmd/xkcd/commands"
+import "github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch/cmd/xkcd/commands"
 
 func main() {
 	commands.Execute()
diff --git a/_examples/xkcdsearch/go.mod b/_examples/xkcdsearch/go.mod
index 2bd0aeb586..a7ddaed2af 100644
--- a/_examples/xkcdsearch/go.mod
+++ b/_examples/xkcdsearch/go.mod
@@ -1,11 +1,11 @@
-module github.com/elastic/go-elasticsearch/_examples/xkcdsearch
+module github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../..
+replace github.com/elastic/go-elasticsearch/v7 => ../..
 
 require (
-	github.com/elastic/go-elasticsearch master
+	github.com/elastic/go-elasticsearch/v7 v7.0.0-20190407092644-3fb2a278216b
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 	github.com/rs/zerolog v1.11.0
 	github.com/spf13/cobra v0.0.3
diff --git a/_examples/xkcdsearch/go.sum b/_examples/xkcdsearch/go.sum
index a4ba203e12..e64a090a87 100644
--- a/_examples/xkcdsearch/go.sum
+++ b/_examples/xkcdsearch/go.sum
@@ -1,3 +1,4 @@
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/rs/zerolog v1.11.0 h1:DRuq/S+4k52uJzBQciUcofXx45GrMC6yrEbb/CoK6+M=
 github.com/rs/zerolog v1.11.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
diff --git a/_examples/xkcdsearch/http.go b/_examples/xkcdsearch/http.go
old mode 100755
new mode 100644
index a2022d8901..1a91d1e97e
--- a/_examples/xkcdsearch/http.go
+++ b/_examples/xkcdsearch/http.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package xkcdsearch
 
 import (
diff --git a/_examples/xkcdsearch/store.go b/_examples/xkcdsearch/store.go
old mode 100755
new mode 100644
index fdd11d26f1..f99e1f1d74
--- a/_examples/xkcdsearch/store.go
+++ b/_examples/xkcdsearch/store.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package xkcdsearch
 
 import (
@@ -8,8 +25,8 @@ import (
 	"io"
 	"strings"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 // SearchResults wraps the Elasticsearch search response.
diff --git a/_examples/xkcdsearch/store_test.go b/_examples/xkcdsearch/store_test.go
old mode 100755
new mode 100644
index ef6f50d50c..5ee26d13b5
--- a/_examples/xkcdsearch/store_test.go
+++ b/_examples/xkcdsearch/store_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package xkcdsearch_test
 
 import (
@@ -11,9 +28,9 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 
-	"github.com/elastic/go-elasticsearch/_examples/xkcdsearch"
+	"github.com/elastic/go-elasticsearch/v7/_examples/xkcdsearch"
 )
 
 var (
@@ -64,6 +81,7 @@ func TestStore(t *testing.T) {
 		Response: &http.Response{
 			StatusCode: http.StatusOK,
 			Body:       ioutil.NopCloser(strings.NewReader(`{}`)),
+			Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
 		},
 	}
 	mocktrans.RoundTripFn = func(req *http.Request) (*http.Response, error) { return mocktrans.Response, nil }
diff --git a/_examples/xkcdsearch/testdata/match_all.json b/_examples/xkcdsearch/testdata/match_all.json
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/testdata/match_query.json b/_examples/xkcdsearch/testdata/match_query.json
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/application.js b/_examples/xkcdsearch/web/application.js
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/assets/fonts/xkcd-script.woff b/_examples/xkcdsearch/web/assets/fonts/xkcd-script.woff
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/assets/images/github-ribbon.svg b/_examples/xkcdsearch/web/assets/images/github-ribbon.svg
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/assets/images/left.png b/_examples/xkcdsearch/web/assets/images/left.png
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/assets/images/middle.png b/_examples/xkcdsearch/web/assets/images/middle.png
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/assets/images/right.png b/_examples/xkcdsearch/web/assets/images/right.png
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/index.html b/_examples/xkcdsearch/web/index.html
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/web/style.css b/_examples/xkcdsearch/web/style.css
old mode 100755
new mode 100644
diff --git a/_examples/xkcdsearch/xkcd.go b/_examples/xkcdsearch/xkcd.go
old mode 100755
new mode 100644
index 238b20fa3d..250b218e3c
--- a/_examples/xkcdsearch/xkcd.go
+++ b/_examples/xkcdsearch/xkcd.go
@@ -1,4 +1,21 @@
-package xkcdsearch // import "github.com/elastic/go-elasticsearch/_examples/xkcdsearch"
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package xkcdsearch
 
 import (
 	"strings"
diff --git a/doc.go b/doc.go
old mode 100755
new mode 100644
index dd1ce83601..2591cbadf2
--- a/doc.go
+++ b/doc.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 /*
 Package elasticsearch provides a Go client for Elasticsearch.
 
@@ -29,6 +46,9 @@ To configure the client, pass a Config object to the NewClient function:
 
 		elasticsearch.NewClient(cfg)
 
+When using the Elastic Service (https://elastic.co/cloud), you can use CloudID instead of Addresses.
+When either Addresses or CloudID is set, the ELASTICSEARCH_URL environment variable is ignored.
+
 See the elasticsearch_integration_test.go file and the _examples folder for more information.
 
 Call the Elasticsearch APIs by invoking the corresponding methods on the client:
@@ -40,6 +60,8 @@ Call the Elasticsearch APIs by invoking the corresponding methods on the client:
 
 		log.Println(res)
 
-See the github.com/elastic/go-elasticsearch/esapi package for more information and examples.
+See the github.com/elastic/go-elasticsearch/esapi package for more information about using the API.
+
+See the github.com/elastic/go-elasticsearch/estransport package for more information about configuring the transport.
 */
 package elasticsearch
diff --git a/elasticsearch.go b/elasticsearch.go
old mode 100755
new mode 100644
index 6e6cecf3a1..db204011c0
--- a/elasticsearch.go
+++ b/elasticsearch.go
@@ -1,20 +1,58 @@
-package elasticsearch // import "github.com/elastic/go-elasticsearch"
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package elasticsearch
 
 import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
 	"errors"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"net/http"
 	"net/url"
 	"os"
+	"regexp"
+	"strconv"
 	"strings"
+	"sync"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+	"github.com/elastic/go-elasticsearch/v7/internal/version"
+)
 
-	"github.com/elastic/go-elasticsearch/esapi"
-	"github.com/elastic/go-elasticsearch/estransport"
-	"github.com/elastic/go-elasticsearch/internal/version"
+var (
+	reVersion *regexp.Regexp
 )
 
+func init() {
+	versionPattern := `^([0-9]+)\.([0-9]+)\.([0-9]+)`
+	reVersion = regexp.MustCompile(versionPattern)
+}
+
 const (
-	defaultURL = "http://localhost:9200"
+	defaultURL         = "http://localhost:9200"
+	tagline            = "You Know, for Search"
+	unknownProduct     = "the client noticed that the server is not Elasticsearch and we do not support this unknown product"
+	unsupportedProduct = "the client noticed that the server is not a supported distribution of Elasticsearch"
 )
 
 // Version returns the package version as a string.
@@ -28,15 +66,64 @@ type Config struct {
 	Username  string   // Username for HTTP Basic Authentication.
 	Password  string   // Password for HTTP Basic Authentication.
 
-	Transport http.RoundTripper  // The HTTP transport object.
-	Logger    estransport.Logger // The logger object.
+	CloudID                string // Endpoint for the Elastic Service (https://elastic.co/cloud).
+	APIKey                 string // Base64-encoded token for authorization; if set, overrides username/password and service token.
+	ServiceToken           string // Service token for authorization; if set, overrides username/password.
+	CertificateFingerprint string // SHA256 hex fingerprint given by Elasticsearch on first launch.
+
+	Header http.Header // Global HTTP request header.
+
+	// PEM-encoded certificate authorities.
+	// When set, an empty certificate pool will be created, and the certificates will be appended to it.
+	// The option is only valid when the transport is not specified, or when it's http.Transport.
+	CACert []byte
+
+	RetryOnStatus        []int // List of status codes for retry. Default: 502, 503, 504.
+	DisableRetry         bool  // Default: false.
+	EnableRetryOnTimeout bool  // Default: false.
+	MaxRetries           int   // Default: 3.
+
+	CompressRequestBody  bool // Default: false.
+	DiscoverNodesOnStart bool // Discover nodes when initializing the client. Default: false.
+
+	DiscoverNodesInterval time.Duration // Discover nodes periodically. Default: disabled.
+
+	EnableMetrics           bool // Enable the metrics collection.
+	EnableDebugLogger       bool // Enable the debug logging.
+	EnableCompatibilityMode bool // Enable sends compatibility header
+
+	DisableMetaHeader    bool // Disable the additional "X-Elastic-Client-Meta" HTTP header.
+	UseResponseCheckOnly bool
+
+	RetryBackoff func(attempt int) time.Duration // Optional backoff duration. Default: nil.
+
+	Transport http.RoundTripper    // The HTTP transport object.
+	Logger    estransport.Logger   // The logger object.
+	Selector  estransport.Selector // The selector object.
+
+	// Optional constructor function for a custom ConnectionPool. Default: nil.
+	ConnectionPoolFunc func([]*estransport.Connection, estransport.Selector) estransport.ConnectionPool
 }
 
 // Client represents the Elasticsearch client.
 //
 type Client struct {
-	*esapi.API // Embeds the API methods
-	Transport  estransport.Interface
+	*esapi.API           // Embeds the API methods
+	Transport            estransport.Interface
+	useResponseCheckOnly bool
+
+	productCheckMu      sync.RWMutex
+	productCheckSuccess bool
+}
+
+type esVersion struct {
+	Number      string `json:"number"`
+	BuildFlavor string `json:"build_flavor"`
+}
+
+type info struct {
+	Version esVersion `json:"version"`
+	Tagline string    `json:"tagline"`
 }
 
 // NewDefaultClient creates a new client with default options.
@@ -57,17 +144,33 @@ func NewDefaultClient() (*Client, error) {
 // It will use the ELASTICSEARCH_URL environment variable, if set,
 // to configure the addresses; use a comma to separate multiple URLs.
 //
-// It's an error to set both cfg.Addresses and the ELASTICSEARCH_URL
-// environment variable.
+// If either cfg.Addresses or cfg.CloudID is set, the ELASTICSEARCH_URL
+// environment variable is ignored.
+//
+// It's an error to set both cfg.Addresses and cfg.CloudID.
 //
 func NewClient(cfg Config) (*Client, error) {
-	envAddrs := addrsFromEnvironment()
+	var addrs []string
 
-	if len(envAddrs) > 0 && len(cfg.Addresses) > 0 {
-		return nil, errors.New("cannot create client: both ELASTICSEARCH_URL and Addresses are set")
-	}
+	if len(cfg.Addresses) == 0 && cfg.CloudID == "" {
+		addrs = addrsFromEnvironment()
+	} else {
+		if len(cfg.Addresses) > 0 && cfg.CloudID != "" {
+			return nil, errors.New("cannot create client: both Addresses and CloudID are set")
+		}
 
-	addrs := append(envAddrs, cfg.Addresses...)
+		if cfg.CloudID != "" {
+			cloudAddr, err := addrFromCloudID(cfg.CloudID)
+			if err != nil {
+				return nil, fmt.Errorf("cannot create client: cannot parse CloudID: %s", err)
+			}
+			addrs = append(addrs, cloudAddr)
+		}
+
+		if len(cfg.Addresses) > 0 {
+			addrs = append(addrs, cfg.Addresses...)
+		}
+	}
 
 	urls, err := addrsToURLs(addrs)
 	if err != nil {
@@ -79,22 +182,232 @@ func NewClient(cfg Config) (*Client, error) {
 		urls = append(urls, u)
 	}
 
-	tp := estransport.New(estransport.Config{
-		URLs:     urls,
-		Username: cfg.Username,
-		Password: cfg.Password,
+	// TODO(karmi): Refactor
+	if urls[0].User != nil {
+		cfg.Username = urls[0].User.Username()
+		pw, _ := urls[0].User.Password()
+		cfg.Password = pw
+	}
 
-		Transport: cfg.Transport,
-		Logger:    cfg.Logger,
+	tp, err := estransport.New(estransport.Config{
+		URLs:                   urls,
+		Username:               cfg.Username,
+		Password:               cfg.Password,
+		APIKey:                 cfg.APIKey,
+		ServiceToken:           cfg.ServiceToken,
+		CertificateFingerprint: cfg.CertificateFingerprint,
+
+		Header: cfg.Header,
+		CACert: cfg.CACert,
+
+		RetryOnStatus:        cfg.RetryOnStatus,
+		DisableRetry:         cfg.DisableRetry,
+		EnableRetryOnTimeout: cfg.EnableRetryOnTimeout,
+		MaxRetries:           cfg.MaxRetries,
+		RetryBackoff:         cfg.RetryBackoff,
+
+		CompressRequestBody: cfg.CompressRequestBody,
+		CompatibilityHeader: cfg.EnableCompatibilityMode,
+
+		EnableMetrics:     cfg.EnableMetrics,
+		EnableDebugLogger: cfg.EnableDebugLogger,
+
+		DisableMetaHeader: cfg.DisableMetaHeader,
+
+		DiscoverNodesInterval: cfg.DiscoverNodesInterval,
+
+		Transport:          cfg.Transport,
+		Logger:             cfg.Logger,
+		Selector:           cfg.Selector,
+		ConnectionPoolFunc: cfg.ConnectionPoolFunc,
 	})
+	if err != nil {
+		return nil, fmt.Errorf("error creating transport: %s", err)
+	}
+
+	client := &Client{Transport: tp, useResponseCheckOnly: cfg.UseResponseCheckOnly}
+	client.API = esapi.New(client)
+
+	if cfg.DiscoverNodesOnStart {
+		go client.DiscoverNodes()
+	}
+
+	return client, err
+}
+
+// genuineCheckHeader validates the presence of the X-Elastic-Product header
+//
+func genuineCheckHeader(header http.Header) error {
+	if header.Get("X-Elastic-Product") != "Elasticsearch" {
+		return errors.New(unknownProduct)
+	}
+	return nil
+}
+
+// genuineCheckInfo validates the informations given by Elasticsearch
+//
+func genuineCheckInfo(info info) error {
+	major, minor, _, err := ParseElasticsearchVersion(info.Version.Number)
+	if err != nil {
+		return err
+	}
 
-	return &Client{Transport: tp, API: esapi.New(tp)}, nil
+	if major < 6 {
+		return errors.New(unknownProduct)
+	}
+	if major < 7 {
+		if info.Tagline != tagline {
+			return errors.New(unknownProduct)
+		}
+	}
+	if major >= 7 {
+		if minor < 14 {
+			if info.Tagline != tagline {
+				return errors.New(unknownProduct)
+			} else if info.Version.BuildFlavor != "default" {
+				return errors.New(unsupportedProduct)
+			}
+		}
+	}
+
+	return nil
+}
+
+// ParseElasticsearchVersion returns an int64 representation of Elasticsearch version.
+//
+func ParseElasticsearchVersion(version string) (int64, int64, int64, error) {
+	matches := reVersion.FindStringSubmatch(version)
+
+	if len(matches) < 4 {
+		return 0, 0, 0, fmt.Errorf("")
+	}
+	major, _ := strconv.ParseInt(matches[1], 10, 0)
+	minor, _ := strconv.ParseInt(matches[2], 10, 0)
+	patch, _ := strconv.ParseInt(matches[3], 10, 0)
+
+	return major, minor, patch, nil
 }
 
 // Perform delegates to Transport to execute a request and return a response.
 //
 func (c *Client) Perform(req *http.Request) (*http.Response, error) {
-	return c.Transport.Perform(req)
+	// ProductCheck validation. We skip this validation of we only want the
+	// header validation. ResponseCheck path continues after original request.
+	if !c.useResponseCheckOnly {
+		// Launch product check for 7.x, request info, check header then payload.
+		if err := c.doProductCheck(req.Context(), c.productCheck); err != nil {
+			return nil, err
+		}
+	}
+
+	// Retrieve the original request.
+	res, err := c.Transport.Perform(req)
+
+	// ResponseCheck path continues, we run the header check on the first answer from ES.
+	if err == nil && (res.StatusCode >= 200 && res.StatusCode < 300){
+		checkHeader := func(context.Context) error {
+			return genuineCheckHeader(res.Header)
+		}
+		if err := c.doProductCheck(req.Context(), checkHeader); err != nil {
+			res.Body.Close()
+			return nil, err
+		}
+	}
+	return res, err
+}
+
+// doProductCheck calls f if there as not been a prior successful call to doProductCheck,
+// returning nil otherwise.
+func (c *Client) doProductCheck(ctx context.Context, f func(context.Context) error) error {
+	c.productCheckMu.RLock()
+	productCheckSuccess := c.productCheckSuccess
+	c.productCheckMu.RUnlock()
+
+	if productCheckSuccess {
+		return nil
+	}
+
+	c.productCheckMu.Lock()
+	defer c.productCheckMu.Unlock()
+
+	if c.productCheckSuccess {
+		return nil
+	}
+
+	if err := f(ctx); err != nil {
+		return err
+	}
+
+	c.productCheckSuccess = true
+
+	return nil
+}
+
+// productCheck runs an esapi.Info query to retrieve informations of the current cluster
+// decodes the response and decides if the cluster is a genuine Elasticsearch product.
+func (c *Client) productCheck(ctx context.Context) error {
+	req := esapi.InfoRequest{}
+	res, err := req.Do(ctx, c.Transport)
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+
+	if res.IsError() {
+		_, err = io.Copy(ioutil.Discard, res.Body)
+		if err != nil {
+			return err
+		}
+		switch res.StatusCode {
+		case http.StatusUnauthorized:
+			return nil
+		case http.StatusForbidden:
+			return nil
+		default:
+			return fmt.Errorf("cannot retrieve informations from Elasticsearch")
+		}
+	}
+
+	err = genuineCheckHeader(res.Header)
+
+	if err != nil {
+		var info info
+		contentType := res.Header.Get("Content-Type")
+		if strings.Contains(contentType, "json") {
+			err = json.NewDecoder(res.Body).Decode(&info)
+			if err != nil {
+				return fmt.Errorf("error decoding Elasticsearch informations: %s", err)
+			}
+		}
+
+		if info.Version.Number != "" {
+			err = genuineCheckInfo(info)
+		}
+	}
+
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Metrics returns the client metrics.
+//
+func (c *Client) Metrics() (estransport.Metrics, error) {
+	if mt, ok := c.Transport.(estransport.Measurable); ok {
+		return mt.Metrics()
+	}
+	return estransport.Metrics{}, errors.New("transport is missing method Metrics()")
+}
+
+// DiscoverNodes reloads the client connections by fetching information from the cluster.
+//
+func (c *Client) DiscoverNodes() error {
+	if dt, ok := c.Transport.(estransport.Discoverable); ok {
+		return dt.DiscoverNodes()
+	}
+	return errors.New("transport is missing method DiscoverNodes()")
 }
 
 // addrsFromEnvironment returns a list of addresses by splitting
@@ -127,3 +440,26 @@ func addrsToURLs(addrs []string) ([]*url.URL, error) {
 	}
 	return urls, nil
 }
+
+// addrFromCloudID extracts the Elasticsearch URL from CloudID.
+// See: https://www.elastic.co/guide/en/cloud/current/ec-cloud-id.html
+//
+func addrFromCloudID(input string) (string, error) {
+	var scheme = "https://"
+
+	values := strings.Split(input, ":")
+	if len(values) != 2 {
+		return "", fmt.Errorf("unexpected format: %q", input)
+	}
+	data, err := base64.StdEncoding.DecodeString(values[1])
+	if err != nil {
+		return "", err
+	}
+	parts := strings.Split(string(data), "$")
+
+	if len(parts) < 2 {
+		return "", fmt.Errorf("invalid encoded value: %s", parts)
+	}
+
+	return fmt.Sprintf("%s%s.%s", scheme, parts[1], parts[0]), nil
+}
diff --git a/elasticsearch_benchmark_test.go b/elasticsearch_benchmark_test.go
old mode 100755
new mode 100644
index b5a1701e61..e0b18bee47
--- a/elasticsearch_benchmark_test.go
+++ b/elasticsearch_benchmark_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package elasticsearch_test
@@ -10,8 +27,8 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 var defaultResponse = http.Response{
@@ -22,16 +39,47 @@ var defaultResponse = http.Response{
 	Body:          ioutil.NopCloser(strings.NewReader(`{}`)),
 }
 
+var infoResponse = http.Response{
+	Status:     "200 OK",
+	StatusCode: http.StatusOK,
+	Header:     http.Header(map[string][]string{"Content-Type": {"application/json"}}),
+}
+
 type FakeTransport struct {
+	InfoResponse *http.Response
 	FakeResponse *http.Response
 }
 
 func (t *FakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	if req.URL.Path == "/" {
+		response := t.InfoResponse
+		response.Body = ioutil.NopCloser(strings.NewReader(`{
+		  "name" : "es1",
+		  "cluster_name" : "go-elasticsearch",
+		  "cluster_uuid" : "clusteruuid",
+		  "version" : {
+			"number" : "7.14.0-SNAPSHOT",
+			"build_flavor" : "default",
+			"build_type" : "docker",
+			"build_hash" : "somehash",
+			"build_date" : "2021-06-09T06:34:20.411011746Z",
+			"build_snapshot" : true,
+			"lucene_version" : "8.9.0",
+			"minimum_wire_compatibility_version" : "6.8.0",
+			"minimum_index_compatibility_version" : "6.0.0-beta1"
+		  },
+		  "tagline" : "You Know, for Search"
+		}`))
+		return t.InfoResponse, nil
+	}
 	return t.FakeResponse, nil
 }
 
 func newFakeTransport(b *testing.B) *FakeTransport {
-	return &FakeTransport{FakeResponse: &defaultResponse}
+	return &FakeTransport{
+		InfoResponse: &infoResponse,
+		FakeResponse: &defaultResponse,
+	}
 }
 
 func BenchmarkClient(b *testing.B) {
@@ -39,7 +87,7 @@ func BenchmarkClient(b *testing.B) {
 
 	b.Run("Create client with defaults", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			_, err := elasticsearch.NewDefaultClient()
+			_, err := elasticsearch.NewClient(elasticsearch.Config{Transport: newFakeTransport(b)})
 
 			if err != nil {
 				b.Fatalf("Unexpected error when creating a client: %s", err)
diff --git a/elasticsearch_example_test.go b/elasticsearch_example_test.go
old mode 100755
new mode 100644
index e05c078079..d8bdcc0a5c
--- a/elasticsearch_example_test.go
+++ b/elasticsearch_example_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package elasticsearch_test
@@ -10,8 +27,8 @@ import (
 	"os"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
 func init() {
@@ -55,7 +72,7 @@ func ExampleNewClient() {
 }
 
 func ExampleNewClient_logger() {
-	// import "github.com/elastic/go-elasticsearch/estransport"
+	// import "github.com/elastic/go-elasticsearch/v7/estransport"
 
 	// Use one of the bundled loggers:
 	//
diff --git a/elasticsearch_integration_test.go b/elasticsearch_integration_test.go
old mode 100755
new mode 100644
index 828ff68069..18a3d0486a
--- a/elasticsearch_integration_test.go
+++ b/elasticsearch_integration_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build integration,!multinode
 
 package elasticsearch_test
@@ -16,14 +33,12 @@ import (
 	"testing"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
 func TestClientTransport(t *testing.T) {
-	t.Parallel()
-
 	t.Run("Persistent", func(t *testing.T) {
 		es, err := elasticsearch.NewDefaultClient()
 		if err != nil {
@@ -57,13 +72,12 @@ func TestClientTransport(t *testing.T) {
 				curTotal = v.HTTP.TotalOpened
 				break
 			}
-			// log.Printf("total_opened: %d", curTotal)
 
 			if curTotal < 1 {
 				t.Errorf("Unexpected total_opened: %d", curTotal)
 			}
 
-			if total < 1 {
+			if total == 0 {
 				total = curTotal
 			}
 
@@ -112,7 +126,7 @@ func TestClientTransport(t *testing.T) {
 		res, err := es.Info(es.Info.WithContext(ctx))
 		if err == nil {
 			res.Body.Close()
-			t.Fatalf("Expected 'context deadline exceeded' error")
+			t.Fatal("Expected 'context deadline exceeded' error")
 		}
 
 		log.Printf("Request cancelled with %T", err)
@@ -136,16 +150,29 @@ func TestClientTransport(t *testing.T) {
 			t.Fatalf("Error creating the client: %s", err)
 		}
 
-		res, err := es.Info()
+		_, err = es.Info()
 		if err == nil {
 			t.Fatalf("Expected error, but got: %v", err)
 		}
 		if _, ok := err.(*net.OpError); !ok {
 			t.Fatalf("Expected net.OpError, but got: %T", err)
 		}
+	})
 
-		if res != nil {
-			t.Fatalf("Unexpected response: %+v", res)
+	t.Run("Compatibility Header", func(t *testing.T) {
+		client, err := elasticsearch.NewClient(elasticsearch.Config{EnableCompatibilityMode: true})
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		res, err := client.Info()
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		contentType := res.Header.Get("content-type")
+		if contentType != "application/vnd.elasticsearch+json;compatible-with=7" {
+			t.Fatalf("Unexpected content-type header, want \"application/vnd.elasticsearch+json;compatible-with=7\", got: %s", contentType)
 		}
 	})
 }
@@ -183,7 +210,7 @@ func TestClientCustomTransport(t *testing.T) {
 	})
 
 	t.Run("Manual", func(t *testing.T) {
-		tr := estransport.New(estransport.Config{
+		tp, _ := estransport.New(estransport.Config{
 			URLs: []*url.URL{
 				{Scheme: "http", Host: "localhost:9200"},
 			},
@@ -191,7 +218,7 @@ func TestClientCustomTransport(t *testing.T) {
 		})
 
 		es := elasticsearch.Client{
-			Transport: tr, API: esapi.New(tr),
+			Transport: tp, API: esapi.New(tp),
 		}
 
 		for i := 0; i < 10; i++ {
diff --git a/elasticsearch_internal_test.go b/elasticsearch_internal_test.go
old mode 100755
new mode 100644
index 55ddd0c005..098a6139a0
--- a/elasticsearch_internal_test.go
+++ b/elasticsearch_internal_test.go
@@ -1,31 +1,93 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package elasticsearch
 
 import (
+	"bytes"
+	"crypto/x509"
+	"encoding/base64"
 	"errors"
+	"io/ioutil"
 	"net/http"
+	"net/http/httptest"
 	"net/url"
 	"os"
+	"reflect"
 	"regexp"
+	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
+var called bool
+
+type mockTransp struct {
+	RoundTripFunc func(*http.Request) (*http.Response, error)
+}
+
+var defaultRoundTripFunc = func(req *http.Request) (*http.Response, error) {
+	response := &http.Response{Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}}}
+
+	if req.URL.Path == "/" {
+		response.Body = ioutil.NopCloser(strings.NewReader(`{
+		  "version" : {
+			"number" : "7.14.0-SNAPSHOT",
+			"build_flavor" : "default"
+		  },
+		  "tagline" : "You Know, for Search"
+		}`))
+		response.Header.Add("Content-Type", "application/json")
+	} else {
+		called = true
+	}
+
+	return response, nil
+}
+
+func (t *mockTransp) RoundTrip(req *http.Request) (*http.Response, error) {
+	if t.RoundTripFunc == nil {
+		return defaultRoundTripFunc(req)
+	}
+	return t.RoundTripFunc(req)
+}
+
 func TestClientConfiguration(t *testing.T) {
 	t.Parallel()
 
 	t.Run("With empty", func(t *testing.T) {
-		_, err := NewDefaultClient()
+		c, err := NewDefaultClient()
 
 		if err != nil {
 			t.Errorf("Unexpected error: %s", err)
 		}
+
+		u := c.Transport.(*estransport.Client).URLs()[0].String()
+
+		if u != defaultURL {
+			t.Errorf("Unexpected URL, want=%s, got=%s", defaultURL, u)
+		}
 	})
 
-	t.Run("With address", func(t *testing.T) {
-		c, err := NewClient(Config{Addresses: []string{"http://localhost:8080//"}})
+	t.Run("With URL from Addresses", func(t *testing.T) {
+		c, err := NewClient(Config{Addresses: []string{"http://localhost:8080//"}, Transport: &mockTransp{}})
 		if err != nil {
 			t.Fatalf("Unexpected error: %s", err)
 		}
@@ -41,7 +103,7 @@ func TestClientConfiguration(t *testing.T) {
 		os.Setenv("ELASTICSEARCH_URL", "http://example.com")
 		defer func() { os.Setenv("ELASTICSEARCH_URL", "") }()
 
-		c, err := NewDefaultClient()
+		c, err := NewClient(Config{Transport: &mockTransp{}})
 		if err != nil {
 			t.Errorf("Unexpected error: %s", err)
 		}
@@ -57,7 +119,36 @@ func TestClientConfiguration(t *testing.T) {
 		os.Setenv("ELASTICSEARCH_URL", "http://example.com")
 		defer func() { os.Setenv("ELASTICSEARCH_URL", "") }()
 
-		_, err := NewClient(Config{Addresses: []string{"http://localhost:8080//"}})
+		c, err := NewClient(Config{Addresses: []string{"http://localhost:8080//"}, Transport: &mockTransp{}})
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		u := c.Transport.(*estransport.Client).URLs()[0].String()
+
+		if u != "http://localhost:8080" {
+			t.Errorf("Unexpected URL, want=http://localhost:8080, got=%s", u)
+		}
+	})
+
+	t.Run("With URL from environment and cfg.CloudID", func(t *testing.T) {
+		os.Setenv("ELASTICSEARCH_URL", "http://example.com")
+		defer func() { os.Setenv("ELASTICSEARCH_URL", "") }()
+
+		c, err := NewClient(Config{CloudID: "foo:YmFyLmNsb3VkLmVzLmlvJGFiYzEyMyRkZWY0NTY=", Transport: &mockTransp{}})
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		u := c.Transport.(*estransport.Client).URLs()[0].String()
+
+		if u != "https://abc123.bar.cloud.es.io" {
+			t.Errorf("Unexpected URL, want=https://abc123.bar.cloud.es.io, got=%s", u)
+		}
+	})
+
+	t.Run("With cfg.Addresses and cfg.CloudID", func(t *testing.T) {
+		_, err := NewClient(Config{Addresses: []string{"http://localhost:8080//"}, CloudID: "foo:ABC="})
 		if err == nil {
 			t.Fatalf("Expected error, got: %v", err)
 		}
@@ -67,6 +158,39 @@ func TestClientConfiguration(t *testing.T) {
 		}
 	})
 
+	t.Run("With CloudID", func(t *testing.T) {
+		// bar.cloud.es.io$abc123$def456
+		c, err := NewClient(Config{CloudID: "foo:YmFyLmNsb3VkLmVzLmlvJGFiYzEyMyRkZWY0NTY=", Transport: &mockTransp{}})
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		u := c.Transport.(*estransport.Client).URLs()[0].String()
+
+		if u != "https://abc123.bar.cloud.es.io" {
+			t.Errorf("Unexpected URL, want=https://abc123.bar.cloud.es.io, got=%s", u)
+		}
+	})
+
+	t.Run("With invalid CloudID", func(t *testing.T) {
+		var err error
+
+		_, err = NewClient(Config{CloudID: "foo:ZZZ==="})
+		if err == nil {
+			t.Errorf("Expected error for CloudID, got: %v", err)
+		}
+
+		_, err = NewClient(Config{CloudID: "foo:Zm9v"})
+		if err == nil {
+			t.Errorf("Expected error for CloudID, got: %v", err)
+		}
+
+		_, err = NewClient(Config{CloudID: "foo:"})
+		if err == nil {
+			t.Errorf("Expected error for CloudID, got: %v", err)
+		}
+	})
+
 	t.Run("With invalid URL", func(t *testing.T) {
 		u := ":foo"
 		_, err := NewClient(Config{Addresses: []string{u}})
@@ -85,15 +209,25 @@ func TestClientConfiguration(t *testing.T) {
 			t.Errorf("Expected error, got: %+v", c)
 		}
 	})
-}
 
-var called bool
-
-type mockTransp struct{}
-
-func (t *mockTransp) RoundTrip(req *http.Request) (*http.Response, error) {
-	called = true
-	return &http.Response{}, nil
+	t.Run("With skip check", func(t *testing.T) {
+		_, err := NewClient(
+			Config{
+				Transport: &mockTransp{
+					RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+						return &http.Response{
+							Header: http.Header{
+								"X-Elastic-Product": []string{"X-Elastic-Product"},
+							},
+							Body: ioutil.NopCloser(strings.NewReader("")),
+						}, nil
+					},
+				},
+			})
+		if err != nil {
+			t.Errorf("Unexpected error, got: %+v", err)
+		}
+	})
 }
 
 func TestClientInterface(t *testing.T) {
@@ -192,8 +326,492 @@ func TestAddrsToURLs(t *testing.T) {
 	}
 }
 
+func TestCloudID(t *testing.T) {
+	t.Run("Parse", func(t *testing.T) {
+		var testdata = []struct {
+			in  string
+			out string
+		}{
+			{
+				in:  "name:" + base64.StdEncoding.EncodeToString([]byte("host$es_uuid$kibana_uuid")),
+				out: "https://es_uuid.host",
+			},
+			{
+				in:  "name:" + base64.StdEncoding.EncodeToString([]byte("host:9243$es_uuid$kibana_uuid")),
+				out: "https://es_uuid.host:9243",
+			},
+			{
+				in:  "name:" + base64.StdEncoding.EncodeToString([]byte("host$es_uuid$")),
+				out: "https://es_uuid.host",
+			},
+			{
+				in:  "name:" + base64.StdEncoding.EncodeToString([]byte("host$es_uuid")),
+				out: "https://es_uuid.host",
+			},
+		}
+
+		for _, tt := range testdata {
+			actual, err := addrFromCloudID(tt.in)
+			if err != nil {
+				t.Errorf("Unexpected error: %s", err)
+			}
+			if actual != tt.out {
+				t.Errorf("Unexpected output, want=%q, got=%q", tt.out, actual)
+			}
+		}
+
+	})
+
+	t.Run("Invalid format", func(t *testing.T) {
+		input := "foobar"
+		_, err := addrFromCloudID(input)
+		if err == nil {
+			t.Errorf("Expected error for input %q, got %v", input, err)
+		}
+		match, _ := regexp.MatchString("unexpected format", err.Error())
+		if !match {
+			t.Errorf("Unexpected error string: %s", err)
+		}
+	})
+
+	t.Run("Invalid base64 value", func(t *testing.T) {
+		input := "foobar:xxxxx"
+		_, err := addrFromCloudID(input)
+		if err == nil {
+			t.Errorf("Expected error for input %q, got %v", input, err)
+		}
+		match, _ := regexp.MatchString("illegal base64 data", err.Error())
+		if !match {
+			t.Errorf("Unexpected error string: %s", err)
+		}
+	})
+}
+
 func TestVersion(t *testing.T) {
 	if Version == "" {
 		t.Error("Version is empty")
 	}
 }
+
+func TestClientMetrics(t *testing.T) {
+	c, _ := NewClient(Config{EnableMetrics: true, Transport: &mockTransp{}})
+
+	m, err := c.Metrics()
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if m.Requests > 1 {
+		t.Errorf("Unexpected output: %s", m)
+	}
+}
+
+func TestParseElasticsearchVersion(t *testing.T) {
+	tests := []struct {
+		name    string
+		version string
+		major   int64
+		minor   int64
+		patch   int64
+		wantErr bool
+	}{
+		{
+			name:    "Nominal version parsing",
+			version: "7.14.0",
+			major:   7,
+			minor:   14,
+			patch:   0,
+			wantErr: false,
+		},
+		{
+			name:    "Snapshot version parsing",
+			version: "7.14.0-SNAPSHOT",
+			major:   7,
+			minor:   14,
+			patch:   0,
+			wantErr: false,
+		},
+		{
+			name:    "Previous major parsing",
+			version: "6.15.1",
+			major:   6,
+			minor:   15,
+			patch:   1,
+			wantErr: false,
+		},
+		{
+			name:    "Error parsing version",
+			version: "6.15",
+			major:   0,
+			minor:   0,
+			patch:   0,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, got1, got2, err := ParseElasticsearchVersion(tt.version)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("ParseElasticsearchVersion() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got != tt.major {
+				t.Errorf("ParseElasticsearchVersion() got = %v, want %v", got, tt.major)
+			}
+			if got1 != tt.minor {
+				t.Errorf("ParseElasticsearchVersion() got1 = %v, want %v", got1, tt.minor)
+			}
+			if got2 != tt.patch {
+				t.Errorf("ParseElasticsearchVersion() got2 = %v, want %v", got2, tt.patch)
+			}
+		})
+	}
+}
+
+func TestGenuineCheckInfo(t *testing.T) {
+	tests := []struct {
+		name    string
+		info    info
+		wantErr bool
+		err 	error
+	}{
+		{
+			name: "Genuine Elasticsearch 7.14.0",
+			info: info{
+				Version: esVersion{
+					Number:      "7.14.0",
+					BuildFlavor: "default",
+				},
+				Tagline: "You Know, for Search",
+			},
+			wantErr: false,
+			err: nil,
+		},
+		{
+			name: "Genuine Elasticsearch 6.15.1",
+			info: info{
+				Version: esVersion{
+					Number:      "6.15.1",
+					BuildFlavor: "default",
+				},
+				Tagline: "You Know, for Search",
+			},
+			wantErr: false,
+			err: nil,
+		},
+		{
+			name: "Not so genuine Elasticsearch 7 major",
+			info: info{
+				Version: esVersion{
+					Number:      "7.12.0",
+					BuildFlavor: "newer",
+				},
+				Tagline: "You Know, for Search",
+			},
+			wantErr: true,
+			err: errors.New(unknownProduct),
+		},
+		{
+			name: "Not so genuine Elasticsearch 6 major",
+			info: info{
+				Version: esVersion{
+					Number:      "6.12.0",
+					BuildFlavor: "default",
+				},
+				Tagline: "You Know, for Fun",
+			},
+			wantErr: true,
+			err: errors.New(unknownProduct),
+		},
+		{
+			name: "Way older Elasticsearch major",
+			info: info{
+				Version: esVersion{
+					Number:      "5.12.0",
+					BuildFlavor: "default",
+				},
+				Tagline: "You Know, for Fun",
+			},
+			wantErr: true,
+			err: errors.New(unknownProduct),
+		},
+		{
+			name: "Elasticsearch oss",
+			info: info{
+				Version: esVersion{
+					Number:      "7.10.0",
+					BuildFlavor: "oss",
+				},
+				Tagline: "You Know, for Search",
+			},
+			wantErr: true,
+			err: errors.New(unsupportedProduct),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := genuineCheckInfo(tt.info); (err != nil) != tt.wantErr && err != tt.err {
+				t.Errorf("genuineCheckInfo() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGenuineCheckHeader(t *testing.T) {
+	tests := []struct {
+		name    string
+		headers http.Header
+		wantErr bool
+	}{
+		{
+			name: "Available and good product header",
+			headers: http.Header{
+				"X-Elastic-Product": []string{"Elasticsearch"},
+			},
+			wantErr: false,
+		},
+		{
+			name: "Available and bad product header",
+			headers: http.Header{
+				"X-Elastic-Product": []string{"Elasticmerch"},
+			},
+			wantErr: true,
+		},
+		{
+			name:    "Unavailable product header",
+			headers: http.Header{},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := genuineCheckHeader(tt.headers); (err != nil) != tt.wantErr {
+				t.Errorf("genuineCheckHeader() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestResponseCheckOnly(t *testing.T) {
+	tests := []struct {
+		name                 string
+		useResponseCheckOnly bool
+		response             *http.Response
+		requestErr           error
+		wantErr              bool
+	}{
+		{
+			name:                 "Valid answer with header",
+			useResponseCheckOnly: false,
+			response: &http.Response{
+				Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
+				Body:   ioutil.NopCloser(strings.NewReader("{}")),
+			},
+			wantErr: false,
+		},
+		{
+			name:                 "Valid answer without header",
+			useResponseCheckOnly: false,
+			response: &http.Response{
+				Body: ioutil.NopCloser(strings.NewReader("{}")),
+			},
+			wantErr: true,
+		},
+		{
+			name:                 "Valid answer with header and response check",
+			useResponseCheckOnly: true,
+			response: &http.Response{
+				Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
+				Body:   ioutil.NopCloser(strings.NewReader("{}")),
+			},
+			wantErr: false,
+		},
+		{
+			name:                 "Valid answer without header and response check",
+			useResponseCheckOnly: true,
+			response: &http.Response{
+				StatusCode: http.StatusOK,
+				Body: ioutil.NopCloser(strings.NewReader("{}")),
+			},
+			wantErr: true,
+		},
+		{
+			name:                 "Request failed",
+			useResponseCheckOnly: true,
+			response:             nil,
+			requestErr:           errors.New("request failed"),
+			wantErr:              true,
+		},
+		{
+			name:                 "Valid request, 500 response",
+			useResponseCheckOnly: false,
+			response:             &http.Response{
+				StatusCode: http.StatusInternalServerError,
+				Body: ioutil.NopCloser(strings.NewReader("")),
+			},
+			requestErr:           nil,
+			wantErr:              true,
+		},
+		{
+			name:                 "Valid request, 404 response",
+			useResponseCheckOnly: false,
+			response:             &http.Response{
+				StatusCode: http.StatusNotFound,
+				Body: ioutil.NopCloser(strings.NewReader("")),
+			},
+			requestErr:           nil,
+			wantErr:              true,
+		},
+		{
+			name:                 "Valid request, 403 response",
+			useResponseCheckOnly: false,
+			response:             &http.Response{
+				StatusCode: http.StatusForbidden,
+				Body: ioutil.NopCloser(strings.NewReader("")),
+			},
+			requestErr:           nil,
+			wantErr:              false,
+		},
+		{
+			name:                 "Valid request, 401 response",
+			useResponseCheckOnly: false,
+			response:             &http.Response{
+				StatusCode: http.StatusUnauthorized,
+				Body: ioutil.NopCloser(strings.NewReader("")),
+			},
+			requestErr:           nil,
+			wantErr:              false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			c, _ := NewClient(Config{
+				Transport: &mockTransp{RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+					return tt.response, tt.requestErr
+				}},
+				UseResponseCheckOnly: tt.useResponseCheckOnly,
+			})
+			_, err := c.Cat.Indices()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Unexpected error, got %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+
+func TestProductCheckError(t *testing.T) {
+	var requestPaths []string
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		requestPaths = append(requestPaths, r.URL.Path)
+		if len(requestPaths) == 1 {
+			// Simulate transient error from a proxy on the first request.
+			// This must not be cached by the client.
+			w.WriteHeader(http.StatusBadGateway)
+			return
+		}
+		w.Header().Set("X-Elastic-Product", "Elasticsearch")
+		w.Write([]byte("{}"))
+	}))
+	defer server.Close()
+
+	c, _ := NewClient(Config{Addresses: []string{server.URL}, DisableRetry: true})
+	if _, err := c.Cat.Indices(); err == nil {
+		t.Fatal("expected error")
+	}
+	if c.productCheckSuccess {
+		t.Fatalf("product check should be invalid, got %v", c.productCheckSuccess)
+	}
+	if _, err := c.Cat.Indices(); err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	if n := len(requestPaths); n != 3 {
+		t.Fatalf("expected 3 requests, got %d", n)
+	}
+	if !reflect.DeepEqual(requestPaths, []string{"/", "/", "/_cat/indices"}) {
+		t.Fatalf("unexpected request paths: %s", requestPaths)
+	}
+	if !c.productCheckSuccess {
+		t.Fatalf("product check should be valid, got : %v", c.productCheckSuccess)
+	}
+}
+
+
+func TestCompatibilityHeader(t *testing.T) {
+	client, err := NewClient(Config{
+		Transport: &mockTransp{RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+			if request.URL.Path == "/" || request.URL.Path == "/test-index/_search" {
+				accept := request.Header.Get("Accept")
+				if accept != "application/vnd.elasticsearch+json;compatible-with=7" {
+					t.Fatalf("Invalid header, expected: %s, got: %s",
+						"application/vnd.elasticsearch+json;compatible-with=7",
+						accept,
+					)
+				}
+
+				if request.URL.Path == "/test-index/_search" {
+					contentType := request.Header.Get("Content-Type")
+					if contentType != "application/vnd.elasticsearch+json;compatible-with=7" {
+						t.Fatalf("Invalid header, expected: %s, got: %s",
+							"application/vnd.elasticsearch+json;compatible-with=7",
+							contentType,
+						)
+					}
+				}
+			} else {
+				t.Fatal("Unexpected route called")
+			}
+
+			return defaultRoundTripFunc(request)
+		}},
+		Addresses:               []string{"http://127.0.0.1:9200"},
+		EnableCompatibilityMode: true,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	client.Info()
+	client.Search(
+		client.Search.WithIndex("test-index"),
+		client.Search.WithBody(strings.NewReader("{}")),
+	)
+}
+
+
+
+func TestFingerprint(t *testing.T) {
+	body := []byte(`{"body": true"}"`)
+	server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("X-Elastic-Product", "Elasticsearch")
+		w.Write(body)
+	}))
+	defer server.Close()
+
+	config := Config{
+		Addresses: []string{server.URL},
+		DisableRetry: true,
+	}
+
+	// Without certificate and authority, client should fail on TLS
+	client, _ := NewClient(config)
+	res, err := client.Info()
+	if _, ok := err.(x509.UnknownAuthorityError); !ok {
+		t.Fatalf("Uknown error, expected UnknownAuthorityError, got: %s", err)
+	}
+
+	// We add the fingerprint corresponding ton testcert.LocalhostCert
+	//
+	config.CertificateFingerprint = "448F628A8A65AA18560E53A80C53ACB38C51B427DF0334082349141147DC9BF6"
+	client, _ = NewClient(config)
+	res, err = client.Info()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+
+	data, _ := ioutil.ReadAll(res.Body)
+	if bytes.Compare(data, body) != 0 {
+		t.Fatalf("unexpected payload returned: expected: %s, got: %s", body, data)
+	}
+}
\ No newline at end of file
diff --git a/esapi/api._.go b/esapi/api._.go
old mode 100644
new mode 100755
index d7821d4a25..576588e58f
--- a/esapi/api._.go
+++ b/esapi/api._.go
@@ -1,138 +1,268 @@
-// Code generated from specification version 7.0.0 (3171bef1d17): DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0 (4a1e55d): DO NOT EDIT
 
 package esapi
 
 // API contains the Elasticsearch APIs
 //
 type API struct {
-	Cat      *Cat
-	Cluster  *Cluster
-	Indices  *Indices
-	Ingest   *Ingest
-	Nodes    *Nodes
-	Remote   *Remote
-	Snapshot *Snapshot
-	Tasks    *Tasks
+	Cat         *Cat
+	Cluster     *Cluster
+	Indices     *Indices
+	Ingest      *Ingest
+	Nodes       *Nodes
+	Remote      *Remote
+	Snapshot    *Snapshot
+	Tasks       *Tasks
+	AsyncSearch *AsyncSearch
+	CCR         *CCR
+	ILM         *ILM
+	License     *License
+	Migration   *Migration
+	ML          *ML
+	Monitoring  *Monitoring
+	Rollup      *Rollup
+	Security    *Security
+	SQL         *SQL
+	SSL         *SSL
+	Watcher     *Watcher
+	XPack       *XPack
 
-	Bulk                    Bulk
-	ClearScroll             ClearScroll
-	Count                   Count
-	Create                  Create
-	Delete                  Delete
-	DeleteByQuery           DeleteByQuery
-	DeleteByQueryRethrottle DeleteByQueryRethrottle
-	DeleteScript            DeleteScript
-	Exists                  Exists
-	ExistsSource            ExistsSource
-	Explain                 Explain
-	FieldCaps               FieldCaps
-	Get                     Get
-	GetScript               GetScript
-	GetSource               GetSource
-	Index                   Index
-	Info                    Info
-	Mget                    Mget
-	Msearch                 Msearch
-	MsearchTemplate         MsearchTemplate
-	Mtermvectors            Mtermvectors
-	Ping                    Ping
-	PutScript               PutScript
-	RankEval                RankEval
-	Reindex                 Reindex
-	ReindexRethrottle       ReindexRethrottle
-	RenderSearchTemplate    RenderSearchTemplate
-	ScriptsPainlessExecute  ScriptsPainlessExecute
-	Scroll                  Scroll
-	Search                  Search
-	SearchShards            SearchShards
-	SearchTemplate          SearchTemplate
-	Termvectors             Termvectors
-	Update                  Update
-	UpdateByQuery           UpdateByQuery
-	UpdateByQueryRethrottle UpdateByQueryRethrottle
+	AutoscalingDeleteAutoscalingPolicy            AutoscalingDeleteAutoscalingPolicy
+	AutoscalingGetAutoscalingCapacity             AutoscalingGetAutoscalingCapacity
+	AutoscalingGetAutoscalingDecision             AutoscalingGetAutoscalingDecision
+	AutoscalingGetAutoscalingPolicy               AutoscalingGetAutoscalingPolicy
+	AutoscalingPutAutoscalingPolicy               AutoscalingPutAutoscalingPolicy
+	Bulk                                          Bulk
+	ClearScroll                                   ClearScroll
+	ClosePointInTime                              ClosePointInTime
+	Count                                         Count
+	Create                                        Create
+	DanglingIndicesDeleteDanglingIndex            DanglingIndicesDeleteDanglingIndex
+	DanglingIndicesImportDanglingIndex            DanglingIndicesImportDanglingIndex
+	DanglingIndicesListDanglingIndices            DanglingIndicesListDanglingIndices
+	DataFrameTransformDeprecatedDeleteTransform   DataFrameTransformDeprecatedDeleteTransform
+	DataFrameTransformDeprecatedGetTransform      DataFrameTransformDeprecatedGetTransform
+	DataFrameTransformDeprecatedGetTransformStats DataFrameTransformDeprecatedGetTransformStats
+	DataFrameTransformDeprecatedPreviewTransform  DataFrameTransformDeprecatedPreviewTransform
+	DataFrameTransformDeprecatedPutTransform      DataFrameTransformDeprecatedPutTransform
+	DataFrameTransformDeprecatedStartTransform    DataFrameTransformDeprecatedStartTransform
+	DataFrameTransformDeprecatedStopTransform     DataFrameTransformDeprecatedStopTransform
+	DataFrameTransformDeprecatedUpdateTransform   DataFrameTransformDeprecatedUpdateTransform
+	DeleteByQuery                                 DeleteByQuery
+	DeleteByQueryRethrottle                       DeleteByQueryRethrottle
+	Delete                                        Delete
+	DeleteScript                                  DeleteScript
+	EnrichDeletePolicy                            EnrichDeletePolicy
+	EnrichExecutePolicy                           EnrichExecutePolicy
+	EnrichGetPolicy                               EnrichGetPolicy
+	EnrichPutPolicy                               EnrichPutPolicy
+	EnrichStats                                   EnrichStats
+	EqlDelete                                     EqlDelete
+	EqlGet                                        EqlGet
+	EqlGetStatus                                  EqlGetStatus
+	EqlSearch                                     EqlSearch
+	Exists                                        Exists
+	ExistsSource                                  ExistsSource
+	Explain                                       Explain
+	FeaturesGetFeatures                           FeaturesGetFeatures
+	FeaturesResetFeatures                         FeaturesResetFeatures
+	FieldCaps                                     FieldCaps
+	FleetGlobalCheckpoints                        FleetGlobalCheckpoints
+	FleetMsearch                                  FleetMsearch
+	FleetSearch                                   FleetSearch
+	Get                                           Get
+	GetScriptContext                              GetScriptContext
+	GetScriptLanguages                            GetScriptLanguages
+	GetScript                                     GetScript
+	GetSource                                     GetSource
+	GraphExplore                                  GraphExplore
+	Index                                         Index
+	Info                                          Info
+	LogstashDeletePipeline                        LogstashDeletePipeline
+	LogstashGetPipeline                           LogstashGetPipeline
+	LogstashPutPipeline                           LogstashPutPipeline
+	Mget                                          Mget
+	Msearch                                       Msearch
+	MsearchTemplate                               MsearchTemplate
+	Mtermvectors                                  Mtermvectors
+	OpenPointInTime                               OpenPointInTime
+	Ping                                          Ping
+	PutScript                                     PutScript
+	RankEval                                      RankEval
+	Reindex                                       Reindex
+	ReindexRethrottle                             ReindexRethrottle
+	RenderSearchTemplate                          RenderSearchTemplate
+	ScriptsPainlessExecute                        ScriptsPainlessExecute
+	Scroll                                        Scroll
+	SearchMvt                                     SearchMvt
+	Search                                        Search
+	SearchShards                                  SearchShards
+	SearchTemplate                                SearchTemplate
+	SearchableSnapshotsCacheStats                 SearchableSnapshotsCacheStats
+	SearchableSnapshotsClearCache                 SearchableSnapshotsClearCache
+	SearchableSnapshotsMount                      SearchableSnapshotsMount
+	SearchableSnapshotsRepositoryStats            SearchableSnapshotsRepositoryStats
+	SearchableSnapshotsStats                      SearchableSnapshotsStats
+	ShutdownDeleteNode                            ShutdownDeleteNode
+	ShutdownGetNode                               ShutdownGetNode
+	ShutdownPutNode                               ShutdownPutNode
+	SlmDeleteLifecycle                            SlmDeleteLifecycle
+	SlmExecuteLifecycle                           SlmExecuteLifecycle
+	SlmExecuteRetention                           SlmExecuteRetention
+	SlmGetLifecycle                               SlmGetLifecycle
+	SlmGetStats                                   SlmGetStats
+	SlmGetStatus                                  SlmGetStatus
+	SlmPutLifecycle                               SlmPutLifecycle
+	SlmStart                                      SlmStart
+	SlmStop                                       SlmStop
+	TermsEnum                                     TermsEnum
+	Termvectors                                   Termvectors
+	TextStructureFindStructure                    TextStructureFindStructure
+	TransformDeleteTransform                      TransformDeleteTransform
+	TransformGetTransform                         TransformGetTransform
+	TransformGetTransformStats                    TransformGetTransformStats
+	TransformPreviewTransform                     TransformPreviewTransform
+	TransformPutTransform                         TransformPutTransform
+	TransformStartTransform                       TransformStartTransform
+	TransformStopTransform                        TransformStopTransform
+	TransformUpdateTransform                      TransformUpdateTransform
+	TransformUpgradeTransforms                    TransformUpgradeTransforms
+	UpdateByQuery                                 UpdateByQuery
+	UpdateByQueryRethrottle                       UpdateByQueryRethrottle
+	Update                                        Update
 }
 
 // Cat contains the Cat APIs
 type Cat struct {
-	Aliases      CatAliases
-	Allocation   CatAllocation
-	Count        CatCount
-	Fielddata    CatFielddata
-	Health       CatHealth
-	Help         CatHelp
-	Indices      CatIndices
-	Master       CatMaster
-	Nodeattrs    CatNodeattrs
-	Nodes        CatNodes
-	PendingTasks CatPendingTasks
-	Plugins      CatPlugins
-	Recovery     CatRecovery
-	Repositories CatRepositories
-	Segments     CatSegments
-	Shards       CatShards
-	Snapshots    CatSnapshots
-	Tasks        CatTasks
-	Templates    CatTemplates
-	ThreadPool   CatThreadPool
+	Aliases              CatAliases
+	Allocation           CatAllocation
+	Count                CatCount
+	Fielddata            CatFielddata
+	Health               CatHealth
+	Help                 CatHelp
+	Indices              CatIndices
+	MLDataFrameAnalytics CatMLDataFrameAnalytics
+	MLDatafeeds          CatMLDatafeeds
+	MLJobs               CatMLJobs
+	MLTrainedModels      CatMLTrainedModels
+	Master               CatMaster
+	Nodeattrs            CatNodeattrs
+	Nodes                CatNodes
+	PendingTasks         CatPendingTasks
+	Plugins              CatPlugins
+	Recovery             CatRecovery
+	Repositories         CatRepositories
+	Segments             CatSegments
+	Shards               CatShards
+	Snapshots            CatSnapshots
+	Tasks                CatTasks
+	Templates            CatTemplates
+	ThreadPool           CatThreadPool
+	Transforms           CatTransforms
 }
 
 // Cluster contains the Cluster APIs
 type Cluster struct {
-	AllocationExplain ClusterAllocationExplain
-	GetSettings       ClusterGetSettings
-	Health            ClusterHealth
-	PendingTasks      ClusterPendingTasks
-	PutSettings       ClusterPutSettings
-	RemoteInfo        ClusterRemoteInfo
-	Reroute           ClusterReroute
-	State             ClusterState
-	Stats             ClusterStats
+	AllocationExplain            ClusterAllocationExplain
+	DeleteComponentTemplate      ClusterDeleteComponentTemplate
+	DeleteVotingConfigExclusions ClusterDeleteVotingConfigExclusions
+	ExistsComponentTemplate      ClusterExistsComponentTemplate
+	GetComponentTemplate         ClusterGetComponentTemplate
+	GetSettings                  ClusterGetSettings
+	Health                       ClusterHealth
+	PendingTasks                 ClusterPendingTasks
+	PostVotingConfigExclusions   ClusterPostVotingConfigExclusions
+	PutComponentTemplate         ClusterPutComponentTemplate
+	PutSettings                  ClusterPutSettings
+	RemoteInfo                   ClusterRemoteInfo
+	Reroute                      ClusterReroute
+	State                        ClusterState
+	Stats                        ClusterStats
 }
 
 // Indices contains the Indices APIs
 type Indices struct {
-	Analyze         IndicesAnalyze
-	ClearCache      IndicesClearCache
-	Close           IndicesClose
-	Create          IndicesCreate
-	Delete          IndicesDelete
-	DeleteAlias     IndicesDeleteAlias
-	DeleteTemplate  IndicesDeleteTemplate
-	Exists          IndicesExists
-	ExistsAlias     IndicesExistsAlias
-	ExistsTemplate  IndicesExistsTemplate
-	ExistsType      IndicesExistsType
-	Flush           IndicesFlush
-	FlushSynced     IndicesFlushSynced
-	Forcemerge      IndicesForcemerge
-	Get             IndicesGet
-	GetAlias        IndicesGetAlias
-	GetFieldMapping IndicesGetFieldMapping
-	GetMapping      IndicesGetMapping
-	GetSettings     IndicesGetSettings
-	GetTemplate     IndicesGetTemplate
-	GetUpgrade      IndicesGetUpgrade
-	Open            IndicesOpen
-	PutAlias        IndicesPutAlias
-	PutMapping      IndicesPutMapping
-	PutSettings     IndicesPutSettings
-	PutTemplate     IndicesPutTemplate
-	Recovery        IndicesRecovery
-	Refresh         IndicesRefresh
-	Rollover        IndicesRollover
-	Segments        IndicesSegments
-	ShardStores     IndicesShardStores
-	Shrink          IndicesShrink
-	Split           IndicesSplit
-	Stats           IndicesStats
-	UpdateAliases   IndicesUpdateAliases
-	Upgrade         IndicesUpgrade
-	ValidateQuery   IndicesValidateQuery
+	AddBlock              IndicesAddBlock
+	Analyze               IndicesAnalyze
+	ClearCache            IndicesClearCache
+	Clone                 IndicesClone
+	Close                 IndicesClose
+	CreateDataStream      IndicesCreateDataStream
+	Create                IndicesCreate
+	DataStreamsStats      IndicesDataStreamsStats
+	DeleteAlias           IndicesDeleteAlias
+	DeleteDataStream      IndicesDeleteDataStream
+	DeleteIndexTemplate   IndicesDeleteIndexTemplate
+	Delete                IndicesDelete
+	DeleteTemplate        IndicesDeleteTemplate
+	DiskUsage             IndicesDiskUsage
+	ExistsAlias           IndicesExistsAlias
+	ExistsDocumentType    IndicesExistsDocumentType
+	ExistsIndexTemplate   IndicesExistsIndexTemplate
+	Exists                IndicesExists
+	ExistsTemplate        IndicesExistsTemplate
+	FieldUsageStats       IndicesFieldUsageStats
+	Flush                 IndicesFlush
+	FlushSynced           IndicesFlushSynced
+	Forcemerge            IndicesForcemerge
+	Freeze                IndicesFreeze
+	GetAlias              IndicesGetAlias
+	GetDataStream         IndicesGetDataStream
+	GetFieldMapping       IndicesGetFieldMapping
+	GetIndexTemplate      IndicesGetIndexTemplate
+	GetMapping            IndicesGetMapping
+	Get                   IndicesGet
+	GetSettings           IndicesGetSettings
+	GetTemplate           IndicesGetTemplate
+	GetUpgrade            IndicesGetUpgrade
+	MigrateToDataStream   IndicesMigrateToDataStream
+	ModifyDataStream      IndicesModifyDataStream
+	Open                  IndicesOpen
+	PromoteDataStream     IndicesPromoteDataStream
+	PutAlias              IndicesPutAlias
+	PutIndexTemplate      IndicesPutIndexTemplate
+	PutMapping            IndicesPutMapping
+	PutSettings           IndicesPutSettings
+	PutTemplate           IndicesPutTemplate
+	Recovery              IndicesRecovery
+	Refresh               IndicesRefresh
+	ReloadSearchAnalyzers IndicesReloadSearchAnalyzers
+	ResolveIndex          IndicesResolveIndex
+	Rollover              IndicesRollover
+	Segments              IndicesSegments
+	ShardStores           IndicesShardStores
+	Shrink                IndicesShrink
+	SimulateIndexTemplate IndicesSimulateIndexTemplate
+	SimulateTemplate      IndicesSimulateTemplate
+	Split                 IndicesSplit
+	Stats                 IndicesStats
+	Unfreeze              IndicesUnfreeze
+	UpdateAliases         IndicesUpdateAliases
+	Upgrade               IndicesUpgrade
+	ValidateQuery         IndicesValidateQuery
 }
 
 // Ingest contains the Ingest APIs
 type Ingest struct {
 	DeletePipeline IngestDeletePipeline
+	GeoIPStats     IngestGeoIPStats
 	GetPipeline    IngestGetPipeline
 	ProcessorGrok  IngestProcessorGrok
 	PutPipeline    IngestPutPipeline
@@ -141,11 +271,15 @@ type Ingest struct {
 
 // Nodes contains the Nodes APIs
 type Nodes struct {
-	HotThreads           NodesHotThreads
-	Info                 NodesInfo
-	ReloadSecureSettings NodesReloadSecureSettings
-	Stats                NodesStats
-	Usage                NodesUsage
+	ClearMeteringArchive             NodesClearMeteringArchive
+	ClearRepositoriesMeteringArchive NodesClearRepositoriesMeteringArchive
+	GetMeteringInfo                  NodesGetMeteringInfo
+	GetRepositoriesMeteringInfo      NodesGetRepositoriesMeteringInfo
+	HotThreads                       NodesHotThreads
+	Info                             NodesInfo
+	ReloadSecureSettings             NodesReloadSecureSettings
+	Stats                            NodesStats
+	Usage                            NodesUsage
 }
 
 // Remote contains the Remote APIs
@@ -154,15 +288,18 @@ type Remote struct {
 
 // Snapshot contains the Snapshot APIs
 type Snapshot struct {
-	Create           SnapshotCreate
-	CreateRepository SnapshotCreateRepository
-	Delete           SnapshotDelete
-	DeleteRepository SnapshotDeleteRepository
-	Get              SnapshotGet
-	GetRepository    SnapshotGetRepository
-	Restore          SnapshotRestore
-	Status           SnapshotStatus
-	VerifyRepository SnapshotVerifyRepository
+	CleanupRepository SnapshotCleanupRepository
+	Clone             SnapshotClone
+	CreateRepository  SnapshotCreateRepository
+	Create            SnapshotCreate
+	DeleteRepository  SnapshotDeleteRepository
+	Delete            SnapshotDelete
+	GetRepository     SnapshotGetRepository
+	Get               SnapshotGet
+	RepositoryAnalyze SnapshotRepositoryAnalyze
+	Restore           SnapshotRestore
+	Status            SnapshotStatus
+	VerifyRepository  SnapshotVerifyRepository
 }
 
 // Tasks contains the Tasks APIs
@@ -172,148 +309,681 @@ type Tasks struct {
 	List   TasksList
 }
 
+// AsyncSearch contains the AsyncSearch APIs
+type AsyncSearch struct {
+	Delete AsyncSearchDelete
+	Get    AsyncSearchGet
+	Status AsyncSearchStatus
+	Submit AsyncSearchSubmit
+}
+
+// CCR contains the CCR APIs
+type CCR struct {
+	DeleteAutoFollowPattern CCRDeleteAutoFollowPattern
+	FollowInfo              CCRFollowInfo
+	Follow                  CCRFollow
+	FollowStats             CCRFollowStats
+	ForgetFollower          CCRForgetFollower
+	GetAutoFollowPattern    CCRGetAutoFollowPattern
+	PauseAutoFollowPattern  CCRPauseAutoFollowPattern
+	PauseFollow             CCRPauseFollow
+	PutAutoFollowPattern    CCRPutAutoFollowPattern
+	ResumeAutoFollowPattern CCRResumeAutoFollowPattern
+	ResumeFollow            CCRResumeFollow
+	Stats                   CCRStats
+	Unfollow                CCRUnfollow
+}
+
+// ILM contains the ILM APIs
+type ILM struct {
+	DeleteLifecycle    ILMDeleteLifecycle
+	ExplainLifecycle   ILMExplainLifecycle
+	GetLifecycle       ILMGetLifecycle
+	GetStatus          ILMGetStatus
+	MigrateToDataTiers ILMMigrateToDataTiers
+	MoveToStep         ILMMoveToStep
+	PutLifecycle       ILMPutLifecycle
+	RemovePolicy       ILMRemovePolicy
+	Retry              ILMRetry
+	Start              ILMStart
+	Stop               ILMStop
+}
+
+// License contains the License APIs
+type License struct {
+	Delete         LicenseDelete
+	GetBasicStatus LicenseGetBasicStatus
+	Get            LicenseGet
+	GetTrialStatus LicenseGetTrialStatus
+	Post           LicensePost
+	PostStartBasic LicensePostStartBasic
+	PostStartTrial LicensePostStartTrial
+}
+
+// Migration contains the Migration APIs
+type Migration struct {
+	Deprecations            MigrationDeprecations
+	GetFeatureUpgradeStatus MigrationGetFeatureUpgradeStatus
+	PostFeatureUpgrade      MigrationPostFeatureUpgrade
+}
+
+// ML contains the ML APIs
+type ML struct {
+	CloseJob                   MLCloseJob
+	DeleteCalendarEvent        MLDeleteCalendarEvent
+	DeleteCalendarJob          MLDeleteCalendarJob
+	DeleteCalendar             MLDeleteCalendar
+	DeleteDataFrameAnalytics   MLDeleteDataFrameAnalytics
+	DeleteDatafeed             MLDeleteDatafeed
+	DeleteExpiredData          MLDeleteExpiredData
+	DeleteFilter               MLDeleteFilter
+	DeleteForecast             MLDeleteForecast
+	DeleteJob                  MLDeleteJob
+	DeleteModelSnapshot        MLDeleteModelSnapshot
+	DeleteTrainedModelAlias    MLDeleteTrainedModelAlias
+	DeleteTrainedModel         MLDeleteTrainedModel
+	EstimateModelMemory        MLEstimateModelMemory
+	EvaluateDataFrame          MLEvaluateDataFrame
+	ExplainDataFrameAnalytics  MLExplainDataFrameAnalytics
+	FindFileStructure          MLFindFileStructure
+	FlushJob                   MLFlushJob
+	Forecast                   MLForecast
+	GetBuckets                 MLGetBuckets
+	GetCalendarEvents          MLGetCalendarEvents
+	GetCalendars               MLGetCalendars
+	GetCategories              MLGetCategories
+	GetDataFrameAnalytics      MLGetDataFrameAnalytics
+	GetDataFrameAnalyticsStats MLGetDataFrameAnalyticsStats
+	GetDatafeedStats           MLGetDatafeedStats
+	GetDatafeeds               MLGetDatafeeds
+	GetFilters                 MLGetFilters
+	GetInfluencers             MLGetInfluencers
+	GetJobStats                MLGetJobStats
+	GetJobs                    MLGetJobs
+	GetModelSnapshots          MLGetModelSnapshots
+	GetOverallBuckets          MLGetOverallBuckets
+	GetRecords                 MLGetRecords
+	GetTrainedModels           MLGetTrainedModels
+	GetTrainedModelsStats      MLGetTrainedModelsStats
+	Info                       MLInfo
+	OpenJob                    MLOpenJob
+	PostCalendarEvents         MLPostCalendarEvents
+	PostData                   MLPostData
+	PreviewDataFrameAnalytics  MLPreviewDataFrameAnalytics
+	PreviewDatafeed            MLPreviewDatafeed
+	PutCalendarJob             MLPutCalendarJob
+	PutCalendar                MLPutCalendar
+	PutDataFrameAnalytics      MLPutDataFrameAnalytics
+	PutDatafeed                MLPutDatafeed
+	PutFilter                  MLPutFilter
+	PutJob                     MLPutJob
+	PutTrainedModelAlias       MLPutTrainedModelAlias
+	PutTrainedModel            MLPutTrainedModel
+	ResetJob                   MLResetJob
+	RevertModelSnapshot        MLRevertModelSnapshot
+	SetUpgradeMode             MLSetUpgradeMode
+	StartDataFrameAnalytics    MLStartDataFrameAnalytics
+	StartDatafeed              MLStartDatafeed
+	StopDataFrameAnalytics     MLStopDataFrameAnalytics
+	StopDatafeed               MLStopDatafeed
+	UpdateDataFrameAnalytics   MLUpdateDataFrameAnalytics
+	UpdateDatafeed             MLUpdateDatafeed
+	UpdateFilter               MLUpdateFilter
+	UpdateJob                  MLUpdateJob
+	UpdateModelSnapshot        MLUpdateModelSnapshot
+	UpgradeJobSnapshot         MLUpgradeJobSnapshot
+	ValidateDetector           MLValidateDetector
+	Validate                   MLValidate
+}
+
+// Monitoring contains the Monitoring APIs
+type Monitoring struct {
+	Bulk MonitoringBulk
+}
+
+// Rollup contains the Rollup APIs
+type Rollup struct {
+	DeleteJob    RollupDeleteJob
+	GetJobs      RollupGetJobs
+	GetCaps      RollupGetRollupCaps
+	GetIndexCaps RollupGetRollupIndexCaps
+	PutJob       RollupPutJob
+	Rollup       RollupRollup
+	Search       RollupRollupSearch
+	StartJob     RollupStartJob
+	StopJob      RollupStopJob
+}
+
+// Security contains the Security APIs
+type Security struct {
+	Authenticate                SecurityAuthenticate
+	ChangePassword              SecurityChangePassword
+	ClearAPIKeyCache            SecurityClearAPIKeyCache
+	ClearCachedPrivileges       SecurityClearCachedPrivileges
+	ClearCachedRealms           SecurityClearCachedRealms
+	ClearCachedRoles            SecurityClearCachedRoles
+	ClearCachedServiceTokens    SecurityClearCachedServiceTokens
+	CreateAPIKey                SecurityCreateAPIKey
+	CreateServiceToken          SecurityCreateServiceToken
+	DeletePrivileges            SecurityDeletePrivileges
+	DeleteRoleMapping           SecurityDeleteRoleMapping
+	DeleteRole                  SecurityDeleteRole
+	DeleteServiceToken          SecurityDeleteServiceToken
+	DeleteUser                  SecurityDeleteUser
+	DisableUser                 SecurityDisableUser
+	EnableUser                  SecurityEnableUser
+	GetAPIKey                   SecurityGetAPIKey
+	GetBuiltinPrivileges        SecurityGetBuiltinPrivileges
+	GetPrivileges               SecurityGetPrivileges
+	GetRoleMapping              SecurityGetRoleMapping
+	GetRole                     SecurityGetRole
+	GetServiceAccounts          SecurityGetServiceAccounts
+	GetServiceCredentials       SecurityGetServiceCredentials
+	GetToken                    SecurityGetToken
+	GetUserPrivileges           SecurityGetUserPrivileges
+	GetUser                     SecurityGetUser
+	GrantAPIKey                 SecurityGrantAPIKey
+	HasPrivileges               SecurityHasPrivileges
+	InvalidateAPIKey            SecurityInvalidateAPIKey
+	InvalidateToken             SecurityInvalidateToken
+	PutPrivileges               SecurityPutPrivileges
+	PutRoleMapping              SecurityPutRoleMapping
+	PutRole                     SecurityPutRole
+	PutUser                     SecurityPutUser
+	QueryAPIKeys                SecurityQueryAPIKeys
+	SamlAuthenticate            SecuritySamlAuthenticate
+	SamlCompleteLogout          SecuritySamlCompleteLogout
+	SamlInvalidate              SecuritySamlInvalidate
+	SamlLogout                  SecuritySamlLogout
+	SamlPrepareAuthentication   SecuritySamlPrepareAuthentication
+	SamlServiceProviderMetadata SecuritySamlServiceProviderMetadata
+}
+
+// SQL contains the SQL APIs
+type SQL struct {
+	ClearCursor    SQLClearCursor
+	DeleteAsync    SQLDeleteAsync
+	GetAsync       SQLGetAsync
+	GetAsyncStatus SQLGetAsyncStatus
+	Query          SQLQuery
+	Translate      SQLTranslate
+}
+
+// SSL contains the SSL APIs
+type SSL struct {
+	Certificates SSLCertificates
+}
+
+// Watcher contains the Watcher APIs
+type Watcher struct {
+	AckWatch        WatcherAckWatch
+	ActivateWatch   WatcherActivateWatch
+	DeactivateWatch WatcherDeactivateWatch
+	DeleteWatch     WatcherDeleteWatch
+	ExecuteWatch    WatcherExecuteWatch
+	GetWatch        WatcherGetWatch
+	PutWatch        WatcherPutWatch
+	QueryWatches    WatcherQueryWatches
+	Start           WatcherStart
+	Stats           WatcherStats
+	Stop            WatcherStop
+}
+
+// XPack contains the XPack APIs
+type XPack struct {
+	Info  XPackInfo
+	Usage XPackUsage
+}
+
 // New creates new API
 //
 func New(t Transport) *API {
 	return &API{
-		Bulk:                    newBulkFunc(t),
-		ClearScroll:             newClearScrollFunc(t),
-		Count:                   newCountFunc(t),
-		Create:                  newCreateFunc(t),
-		Delete:                  newDeleteFunc(t),
-		DeleteByQuery:           newDeleteByQueryFunc(t),
-		DeleteByQueryRethrottle: newDeleteByQueryRethrottleFunc(t),
-		DeleteScript:            newDeleteScriptFunc(t),
-		Exists:                  newExistsFunc(t),
-		ExistsSource:            newExistsSourceFunc(t),
-		Explain:                 newExplainFunc(t),
-		FieldCaps:               newFieldCapsFunc(t),
-		Get:                     newGetFunc(t),
-		GetScript:               newGetScriptFunc(t),
-		GetSource:               newGetSourceFunc(t),
-		Index:                   newIndexFunc(t),
-		Info:                    newInfoFunc(t),
-		Mget:                    newMgetFunc(t),
-		Msearch:                 newMsearchFunc(t),
-		MsearchTemplate:         newMsearchTemplateFunc(t),
-		Mtermvectors:            newMtermvectorsFunc(t),
-		Ping:                    newPingFunc(t),
-		PutScript:               newPutScriptFunc(t),
-		RankEval:                newRankEvalFunc(t),
-		Reindex:                 newReindexFunc(t),
-		ReindexRethrottle:       newReindexRethrottleFunc(t),
-		RenderSearchTemplate:    newRenderSearchTemplateFunc(t),
-		ScriptsPainlessExecute:  newScriptsPainlessExecuteFunc(t),
-		Scroll:                  newScrollFunc(t),
-		Search:                  newSearchFunc(t),
-		SearchShards:            newSearchShardsFunc(t),
-		SearchTemplate:          newSearchTemplateFunc(t),
-		Termvectors:             newTermvectorsFunc(t),
-		Update:                  newUpdateFunc(t),
-		UpdateByQuery:           newUpdateByQueryFunc(t),
-		UpdateByQueryRethrottle: newUpdateByQueryRethrottleFunc(t),
+		AutoscalingDeleteAutoscalingPolicy:            newAutoscalingDeleteAutoscalingPolicyFunc(t),
+		AutoscalingGetAutoscalingCapacity:             newAutoscalingGetAutoscalingCapacityFunc(t),
+		AutoscalingGetAutoscalingDecision:             newAutoscalingGetAutoscalingDecisionFunc(t),
+		AutoscalingGetAutoscalingPolicy:               newAutoscalingGetAutoscalingPolicyFunc(t),
+		AutoscalingPutAutoscalingPolicy:               newAutoscalingPutAutoscalingPolicyFunc(t),
+		Bulk:                                          newBulkFunc(t),
+		ClearScroll:                                   newClearScrollFunc(t),
+		ClosePointInTime:                              newClosePointInTimeFunc(t),
+		Count:                                         newCountFunc(t),
+		Create:                                        newCreateFunc(t),
+		DanglingIndicesDeleteDanglingIndex:            newDanglingIndicesDeleteDanglingIndexFunc(t),
+		DanglingIndicesImportDanglingIndex:            newDanglingIndicesImportDanglingIndexFunc(t),
+		DanglingIndicesListDanglingIndices:            newDanglingIndicesListDanglingIndicesFunc(t),
+		DataFrameTransformDeprecatedDeleteTransform:   newDataFrameTransformDeprecatedDeleteTransformFunc(t),
+		DataFrameTransformDeprecatedGetTransform:      newDataFrameTransformDeprecatedGetTransformFunc(t),
+		DataFrameTransformDeprecatedGetTransformStats: newDataFrameTransformDeprecatedGetTransformStatsFunc(t),
+		DataFrameTransformDeprecatedPreviewTransform:  newDataFrameTransformDeprecatedPreviewTransformFunc(t),
+		DataFrameTransformDeprecatedPutTransform:      newDataFrameTransformDeprecatedPutTransformFunc(t),
+		DataFrameTransformDeprecatedStartTransform:    newDataFrameTransformDeprecatedStartTransformFunc(t),
+		DataFrameTransformDeprecatedStopTransform:     newDataFrameTransformDeprecatedStopTransformFunc(t),
+		DataFrameTransformDeprecatedUpdateTransform:   newDataFrameTransformDeprecatedUpdateTransformFunc(t),
+		DeleteByQuery:                                 newDeleteByQueryFunc(t),
+		DeleteByQueryRethrottle:                       newDeleteByQueryRethrottleFunc(t),
+		Delete:                                        newDeleteFunc(t),
+		DeleteScript:                                  newDeleteScriptFunc(t),
+		EnrichDeletePolicy:                            newEnrichDeletePolicyFunc(t),
+		EnrichExecutePolicy:                           newEnrichExecutePolicyFunc(t),
+		EnrichGetPolicy:                               newEnrichGetPolicyFunc(t),
+		EnrichPutPolicy:                               newEnrichPutPolicyFunc(t),
+		EnrichStats:                                   newEnrichStatsFunc(t),
+		EqlDelete:                                     newEqlDeleteFunc(t),
+		EqlGet:                                        newEqlGetFunc(t),
+		EqlGetStatus:                                  newEqlGetStatusFunc(t),
+		EqlSearch:                                     newEqlSearchFunc(t),
+		Exists:                                        newExistsFunc(t),
+		ExistsSource:                                  newExistsSourceFunc(t),
+		Explain:                                       newExplainFunc(t),
+		FeaturesGetFeatures:                           newFeaturesGetFeaturesFunc(t),
+		FeaturesResetFeatures:                         newFeaturesResetFeaturesFunc(t),
+		FieldCaps:                                     newFieldCapsFunc(t),
+		FleetGlobalCheckpoints:                        newFleetGlobalCheckpointsFunc(t),
+		FleetMsearch:                                  newFleetMsearchFunc(t),
+		FleetSearch:                                   newFleetSearchFunc(t),
+		Get:                                           newGetFunc(t),
+		GetScriptContext:                              newGetScriptContextFunc(t),
+		GetScriptLanguages:                            newGetScriptLanguagesFunc(t),
+		GetScript:                                     newGetScriptFunc(t),
+		GetSource:                                     newGetSourceFunc(t),
+		GraphExplore:                                  newGraphExploreFunc(t),
+		Index:                                         newIndexFunc(t),
+		Info:                                          newInfoFunc(t),
+		LogstashDeletePipeline:                        newLogstashDeletePipelineFunc(t),
+		LogstashGetPipeline:                           newLogstashGetPipelineFunc(t),
+		LogstashPutPipeline:                           newLogstashPutPipelineFunc(t),
+		Mget:                                          newMgetFunc(t),
+		Msearch:                                       newMsearchFunc(t),
+		MsearchTemplate:                               newMsearchTemplateFunc(t),
+		Mtermvectors:                                  newMtermvectorsFunc(t),
+		OpenPointInTime:                               newOpenPointInTimeFunc(t),
+		Ping:                                          newPingFunc(t),
+		PutScript:                                     newPutScriptFunc(t),
+		RankEval:                                      newRankEvalFunc(t),
+		Reindex:                                       newReindexFunc(t),
+		ReindexRethrottle:                             newReindexRethrottleFunc(t),
+		RenderSearchTemplate:                          newRenderSearchTemplateFunc(t),
+		ScriptsPainlessExecute:                        newScriptsPainlessExecuteFunc(t),
+		Scroll:                                        newScrollFunc(t),
+		SearchMvt:                                     newSearchMvtFunc(t),
+		Search:                                        newSearchFunc(t),
+		SearchShards:                                  newSearchShardsFunc(t),
+		SearchTemplate:                                newSearchTemplateFunc(t),
+		SearchableSnapshotsCacheStats:                 newSearchableSnapshotsCacheStatsFunc(t),
+		SearchableSnapshotsClearCache:                 newSearchableSnapshotsClearCacheFunc(t),
+		SearchableSnapshotsMount:                      newSearchableSnapshotsMountFunc(t),
+		SearchableSnapshotsRepositoryStats:            newSearchableSnapshotsRepositoryStatsFunc(t),
+		SearchableSnapshotsStats:                      newSearchableSnapshotsStatsFunc(t),
+		ShutdownDeleteNode:                            newShutdownDeleteNodeFunc(t),
+		ShutdownGetNode:                               newShutdownGetNodeFunc(t),
+		ShutdownPutNode:                               newShutdownPutNodeFunc(t),
+		SlmDeleteLifecycle:                            newSlmDeleteLifecycleFunc(t),
+		SlmExecuteLifecycle:                           newSlmExecuteLifecycleFunc(t),
+		SlmExecuteRetention:                           newSlmExecuteRetentionFunc(t),
+		SlmGetLifecycle:                               newSlmGetLifecycleFunc(t),
+		SlmGetStats:                                   newSlmGetStatsFunc(t),
+		SlmGetStatus:                                  newSlmGetStatusFunc(t),
+		SlmPutLifecycle:                               newSlmPutLifecycleFunc(t),
+		SlmStart:                                      newSlmStartFunc(t),
+		SlmStop:                                       newSlmStopFunc(t),
+		TermsEnum:                                     newTermsEnumFunc(t),
+		Termvectors:                                   newTermvectorsFunc(t),
+		TextStructureFindStructure:                    newTextStructureFindStructureFunc(t),
+		TransformDeleteTransform:                      newTransformDeleteTransformFunc(t),
+		TransformGetTransform:                         newTransformGetTransformFunc(t),
+		TransformGetTransformStats:                    newTransformGetTransformStatsFunc(t),
+		TransformPreviewTransform:                     newTransformPreviewTransformFunc(t),
+		TransformPutTransform:                         newTransformPutTransformFunc(t),
+		TransformStartTransform:                       newTransformStartTransformFunc(t),
+		TransformStopTransform:                        newTransformStopTransformFunc(t),
+		TransformUpdateTransform:                      newTransformUpdateTransformFunc(t),
+		TransformUpgradeTransforms:                    newTransformUpgradeTransformsFunc(t),
+		UpdateByQuery:                                 newUpdateByQueryFunc(t),
+		UpdateByQueryRethrottle:                       newUpdateByQueryRethrottleFunc(t),
+		Update:                                        newUpdateFunc(t),
 		Cat: &Cat{
-			Aliases:      newCatAliasesFunc(t),
-			Allocation:   newCatAllocationFunc(t),
-			Count:        newCatCountFunc(t),
-			Fielddata:    newCatFielddataFunc(t),
-			Health:       newCatHealthFunc(t),
-			Help:         newCatHelpFunc(t),
-			Indices:      newCatIndicesFunc(t),
-			Master:       newCatMasterFunc(t),
-			Nodeattrs:    newCatNodeattrsFunc(t),
-			Nodes:        newCatNodesFunc(t),
-			PendingTasks: newCatPendingTasksFunc(t),
-			Plugins:      newCatPluginsFunc(t),
-			Recovery:     newCatRecoveryFunc(t),
-			Repositories: newCatRepositoriesFunc(t),
-			Segments:     newCatSegmentsFunc(t),
-			Shards:       newCatShardsFunc(t),
-			Snapshots:    newCatSnapshotsFunc(t),
-			Tasks:        newCatTasksFunc(t),
-			Templates:    newCatTemplatesFunc(t),
-			ThreadPool:   newCatThreadPoolFunc(t),
+			Aliases:              newCatAliasesFunc(t),
+			Allocation:           newCatAllocationFunc(t),
+			Count:                newCatCountFunc(t),
+			Fielddata:            newCatFielddataFunc(t),
+			Health:               newCatHealthFunc(t),
+			Help:                 newCatHelpFunc(t),
+			Indices:              newCatIndicesFunc(t),
+			MLDataFrameAnalytics: newCatMLDataFrameAnalyticsFunc(t),
+			MLDatafeeds:          newCatMLDatafeedsFunc(t),
+			MLJobs:               newCatMLJobsFunc(t),
+			MLTrainedModels:      newCatMLTrainedModelsFunc(t),
+			Master:               newCatMasterFunc(t),
+			Nodeattrs:            newCatNodeattrsFunc(t),
+			Nodes:                newCatNodesFunc(t),
+			PendingTasks:         newCatPendingTasksFunc(t),
+			Plugins:              newCatPluginsFunc(t),
+			Recovery:             newCatRecoveryFunc(t),
+			Repositories:         newCatRepositoriesFunc(t),
+			Segments:             newCatSegmentsFunc(t),
+			Shards:               newCatShardsFunc(t),
+			Snapshots:            newCatSnapshotsFunc(t),
+			Tasks:                newCatTasksFunc(t),
+			Templates:            newCatTemplatesFunc(t),
+			ThreadPool:           newCatThreadPoolFunc(t),
+			Transforms:           newCatTransformsFunc(t),
 		},
 		Cluster: &Cluster{
-			AllocationExplain: newClusterAllocationExplainFunc(t),
-			GetSettings:       newClusterGetSettingsFunc(t),
-			Health:            newClusterHealthFunc(t),
-			PendingTasks:      newClusterPendingTasksFunc(t),
-			PutSettings:       newClusterPutSettingsFunc(t),
-			RemoteInfo:        newClusterRemoteInfoFunc(t),
-			Reroute:           newClusterRerouteFunc(t),
-			State:             newClusterStateFunc(t),
-			Stats:             newClusterStatsFunc(t),
+			AllocationExplain:            newClusterAllocationExplainFunc(t),
+			DeleteComponentTemplate:      newClusterDeleteComponentTemplateFunc(t),
+			DeleteVotingConfigExclusions: newClusterDeleteVotingConfigExclusionsFunc(t),
+			ExistsComponentTemplate:      newClusterExistsComponentTemplateFunc(t),
+			GetComponentTemplate:         newClusterGetComponentTemplateFunc(t),
+			GetSettings:                  newClusterGetSettingsFunc(t),
+			Health:                       newClusterHealthFunc(t),
+			PendingTasks:                 newClusterPendingTasksFunc(t),
+			PostVotingConfigExclusions:   newClusterPostVotingConfigExclusionsFunc(t),
+			PutComponentTemplate:         newClusterPutComponentTemplateFunc(t),
+			PutSettings:                  newClusterPutSettingsFunc(t),
+			RemoteInfo:                   newClusterRemoteInfoFunc(t),
+			Reroute:                      newClusterRerouteFunc(t),
+			State:                        newClusterStateFunc(t),
+			Stats:                        newClusterStatsFunc(t),
 		},
 		Indices: &Indices{
-			Analyze:         newIndicesAnalyzeFunc(t),
-			ClearCache:      newIndicesClearCacheFunc(t),
-			Close:           newIndicesCloseFunc(t),
-			Create:          newIndicesCreateFunc(t),
-			Delete:          newIndicesDeleteFunc(t),
-			DeleteAlias:     newIndicesDeleteAliasFunc(t),
-			DeleteTemplate:  newIndicesDeleteTemplateFunc(t),
-			Exists:          newIndicesExistsFunc(t),
-			ExistsAlias:     newIndicesExistsAliasFunc(t),
-			ExistsTemplate:  newIndicesExistsTemplateFunc(t),
-			ExistsType:      newIndicesExistsTypeFunc(t),
-			Flush:           newIndicesFlushFunc(t),
-			FlushSynced:     newIndicesFlushSyncedFunc(t),
-			Forcemerge:      newIndicesForcemergeFunc(t),
-			Get:             newIndicesGetFunc(t),
-			GetAlias:        newIndicesGetAliasFunc(t),
-			GetFieldMapping: newIndicesGetFieldMappingFunc(t),
-			GetMapping:      newIndicesGetMappingFunc(t),
-			GetSettings:     newIndicesGetSettingsFunc(t),
-			GetTemplate:     newIndicesGetTemplateFunc(t),
-			GetUpgrade:      newIndicesGetUpgradeFunc(t),
-			Open:            newIndicesOpenFunc(t),
-			PutAlias:        newIndicesPutAliasFunc(t),
-			PutMapping:      newIndicesPutMappingFunc(t),
-			PutSettings:     newIndicesPutSettingsFunc(t),
-			PutTemplate:     newIndicesPutTemplateFunc(t),
-			Recovery:        newIndicesRecoveryFunc(t),
-			Refresh:         newIndicesRefreshFunc(t),
-			Rollover:        newIndicesRolloverFunc(t),
-			Segments:        newIndicesSegmentsFunc(t),
-			ShardStores:     newIndicesShardStoresFunc(t),
-			Shrink:          newIndicesShrinkFunc(t),
-			Split:           newIndicesSplitFunc(t),
-			Stats:           newIndicesStatsFunc(t),
-			UpdateAliases:   newIndicesUpdateAliasesFunc(t),
-			Upgrade:         newIndicesUpgradeFunc(t),
-			ValidateQuery:   newIndicesValidateQueryFunc(t),
+			AddBlock:              newIndicesAddBlockFunc(t),
+			Analyze:               newIndicesAnalyzeFunc(t),
+			ClearCache:            newIndicesClearCacheFunc(t),
+			Clone:                 newIndicesCloneFunc(t),
+			Close:                 newIndicesCloseFunc(t),
+			CreateDataStream:      newIndicesCreateDataStreamFunc(t),
+			Create:                newIndicesCreateFunc(t),
+			DataStreamsStats:      newIndicesDataStreamsStatsFunc(t),
+			DeleteAlias:           newIndicesDeleteAliasFunc(t),
+			DeleteDataStream:      newIndicesDeleteDataStreamFunc(t),
+			DeleteIndexTemplate:   newIndicesDeleteIndexTemplateFunc(t),
+			Delete:                newIndicesDeleteFunc(t),
+			DeleteTemplate:        newIndicesDeleteTemplateFunc(t),
+			DiskUsage:             newIndicesDiskUsageFunc(t),
+			ExistsAlias:           newIndicesExistsAliasFunc(t),
+			ExistsDocumentType:    newIndicesExistsDocumentTypeFunc(t),
+			ExistsIndexTemplate:   newIndicesExistsIndexTemplateFunc(t),
+			Exists:                newIndicesExistsFunc(t),
+			ExistsTemplate:        newIndicesExistsTemplateFunc(t),
+			FieldUsageStats:       newIndicesFieldUsageStatsFunc(t),
+			Flush:                 newIndicesFlushFunc(t),
+			FlushSynced:           newIndicesFlushSyncedFunc(t),
+			Forcemerge:            newIndicesForcemergeFunc(t),
+			Freeze:                newIndicesFreezeFunc(t),
+			GetAlias:              newIndicesGetAliasFunc(t),
+			GetDataStream:         newIndicesGetDataStreamFunc(t),
+			GetFieldMapping:       newIndicesGetFieldMappingFunc(t),
+			GetIndexTemplate:      newIndicesGetIndexTemplateFunc(t),
+			GetMapping:            newIndicesGetMappingFunc(t),
+			Get:                   newIndicesGetFunc(t),
+			GetSettings:           newIndicesGetSettingsFunc(t),
+			GetTemplate:           newIndicesGetTemplateFunc(t),
+			GetUpgrade:            newIndicesGetUpgradeFunc(t),
+			MigrateToDataStream:   newIndicesMigrateToDataStreamFunc(t),
+			ModifyDataStream:      newIndicesModifyDataStreamFunc(t),
+			Open:                  newIndicesOpenFunc(t),
+			PromoteDataStream:     newIndicesPromoteDataStreamFunc(t),
+			PutAlias:              newIndicesPutAliasFunc(t),
+			PutIndexTemplate:      newIndicesPutIndexTemplateFunc(t),
+			PutMapping:            newIndicesPutMappingFunc(t),
+			PutSettings:           newIndicesPutSettingsFunc(t),
+			PutTemplate:           newIndicesPutTemplateFunc(t),
+			Recovery:              newIndicesRecoveryFunc(t),
+			Refresh:               newIndicesRefreshFunc(t),
+			ReloadSearchAnalyzers: newIndicesReloadSearchAnalyzersFunc(t),
+			ResolveIndex:          newIndicesResolveIndexFunc(t),
+			Rollover:              newIndicesRolloverFunc(t),
+			Segments:              newIndicesSegmentsFunc(t),
+			ShardStores:           newIndicesShardStoresFunc(t),
+			Shrink:                newIndicesShrinkFunc(t),
+			SimulateIndexTemplate: newIndicesSimulateIndexTemplateFunc(t),
+			SimulateTemplate:      newIndicesSimulateTemplateFunc(t),
+			Split:                 newIndicesSplitFunc(t),
+			Stats:                 newIndicesStatsFunc(t),
+			Unfreeze:              newIndicesUnfreezeFunc(t),
+			UpdateAliases:         newIndicesUpdateAliasesFunc(t),
+			Upgrade:               newIndicesUpgradeFunc(t),
+			ValidateQuery:         newIndicesValidateQueryFunc(t),
 		},
 		Ingest: &Ingest{
 			DeletePipeline: newIngestDeletePipelineFunc(t),
+			GeoIPStats:     newIngestGeoIPStatsFunc(t),
 			GetPipeline:    newIngestGetPipelineFunc(t),
 			ProcessorGrok:  newIngestProcessorGrokFunc(t),
 			PutPipeline:    newIngestPutPipelineFunc(t),
 			Simulate:       newIngestSimulateFunc(t),
 		},
 		Nodes: &Nodes{
-			HotThreads:           newNodesHotThreadsFunc(t),
-			Info:                 newNodesInfoFunc(t),
-			ReloadSecureSettings: newNodesReloadSecureSettingsFunc(t),
-			Stats:                newNodesStatsFunc(t),
-			Usage:                newNodesUsageFunc(t),
+			ClearMeteringArchive:             newNodesClearMeteringArchiveFunc(t),
+			ClearRepositoriesMeteringArchive: newNodesClearRepositoriesMeteringArchiveFunc(t),
+			GetMeteringInfo:                  newNodesGetMeteringInfoFunc(t),
+			GetRepositoriesMeteringInfo:      newNodesGetRepositoriesMeteringInfoFunc(t),
+			HotThreads:                       newNodesHotThreadsFunc(t),
+			Info:                             newNodesInfoFunc(t),
+			ReloadSecureSettings:             newNodesReloadSecureSettingsFunc(t),
+			Stats:                            newNodesStatsFunc(t),
+			Usage:                            newNodesUsageFunc(t),
 		},
 		Remote: &Remote{},
 		Snapshot: &Snapshot{
-			Create:           newSnapshotCreateFunc(t),
-			CreateRepository: newSnapshotCreateRepositoryFunc(t),
-			Delete:           newSnapshotDeleteFunc(t),
-			DeleteRepository: newSnapshotDeleteRepositoryFunc(t),
-			Get:              newSnapshotGetFunc(t),
-			GetRepository:    newSnapshotGetRepositoryFunc(t),
-			Restore:          newSnapshotRestoreFunc(t),
-			Status:           newSnapshotStatusFunc(t),
-			VerifyRepository: newSnapshotVerifyRepositoryFunc(t),
+			CleanupRepository: newSnapshotCleanupRepositoryFunc(t),
+			Clone:             newSnapshotCloneFunc(t),
+			CreateRepository:  newSnapshotCreateRepositoryFunc(t),
+			Create:            newSnapshotCreateFunc(t),
+			DeleteRepository:  newSnapshotDeleteRepositoryFunc(t),
+			Delete:            newSnapshotDeleteFunc(t),
+			GetRepository:     newSnapshotGetRepositoryFunc(t),
+			Get:               newSnapshotGetFunc(t),
+			RepositoryAnalyze: newSnapshotRepositoryAnalyzeFunc(t),
+			Restore:           newSnapshotRestoreFunc(t),
+			Status:            newSnapshotStatusFunc(t),
+			VerifyRepository:  newSnapshotVerifyRepositoryFunc(t),
 		},
 		Tasks: &Tasks{
 			Cancel: newTasksCancelFunc(t),
 			Get:    newTasksGetFunc(t),
 			List:   newTasksListFunc(t),
 		},
+		AsyncSearch: &AsyncSearch{
+			Delete: newAsyncSearchDeleteFunc(t),
+			Get:    newAsyncSearchGetFunc(t),
+			Status: newAsyncSearchStatusFunc(t),
+			Submit: newAsyncSearchSubmitFunc(t),
+		},
+		CCR: &CCR{
+			DeleteAutoFollowPattern: newCCRDeleteAutoFollowPatternFunc(t),
+			FollowInfo:              newCCRFollowInfoFunc(t),
+			Follow:                  newCCRFollowFunc(t),
+			FollowStats:             newCCRFollowStatsFunc(t),
+			ForgetFollower:          newCCRForgetFollowerFunc(t),
+			GetAutoFollowPattern:    newCCRGetAutoFollowPatternFunc(t),
+			PauseAutoFollowPattern:  newCCRPauseAutoFollowPatternFunc(t),
+			PauseFollow:             newCCRPauseFollowFunc(t),
+			PutAutoFollowPattern:    newCCRPutAutoFollowPatternFunc(t),
+			ResumeAutoFollowPattern: newCCRResumeAutoFollowPatternFunc(t),
+			ResumeFollow:            newCCRResumeFollowFunc(t),
+			Stats:                   newCCRStatsFunc(t),
+			Unfollow:                newCCRUnfollowFunc(t),
+		},
+		ILM: &ILM{
+			DeleteLifecycle:    newILMDeleteLifecycleFunc(t),
+			ExplainLifecycle:   newILMExplainLifecycleFunc(t),
+			GetLifecycle:       newILMGetLifecycleFunc(t),
+			GetStatus:          newILMGetStatusFunc(t),
+			MigrateToDataTiers: newILMMigrateToDataTiersFunc(t),
+			MoveToStep:         newILMMoveToStepFunc(t),
+			PutLifecycle:       newILMPutLifecycleFunc(t),
+			RemovePolicy:       newILMRemovePolicyFunc(t),
+			Retry:              newILMRetryFunc(t),
+			Start:              newILMStartFunc(t),
+			Stop:               newILMStopFunc(t),
+		},
+		License: &License{
+			Delete:         newLicenseDeleteFunc(t),
+			GetBasicStatus: newLicenseGetBasicStatusFunc(t),
+			Get:            newLicenseGetFunc(t),
+			GetTrialStatus: newLicenseGetTrialStatusFunc(t),
+			Post:           newLicensePostFunc(t),
+			PostStartBasic: newLicensePostStartBasicFunc(t),
+			PostStartTrial: newLicensePostStartTrialFunc(t),
+		},
+		Migration: &Migration{
+			Deprecations:            newMigrationDeprecationsFunc(t),
+			GetFeatureUpgradeStatus: newMigrationGetFeatureUpgradeStatusFunc(t),
+			PostFeatureUpgrade:      newMigrationPostFeatureUpgradeFunc(t),
+		},
+		ML: &ML{
+			CloseJob:                   newMLCloseJobFunc(t),
+			DeleteCalendarEvent:        newMLDeleteCalendarEventFunc(t),
+			DeleteCalendarJob:          newMLDeleteCalendarJobFunc(t),
+			DeleteCalendar:             newMLDeleteCalendarFunc(t),
+			DeleteDataFrameAnalytics:   newMLDeleteDataFrameAnalyticsFunc(t),
+			DeleteDatafeed:             newMLDeleteDatafeedFunc(t),
+			DeleteExpiredData:          newMLDeleteExpiredDataFunc(t),
+			DeleteFilter:               newMLDeleteFilterFunc(t),
+			DeleteForecast:             newMLDeleteForecastFunc(t),
+			DeleteJob:                  newMLDeleteJobFunc(t),
+			DeleteModelSnapshot:        newMLDeleteModelSnapshotFunc(t),
+			DeleteTrainedModelAlias:    newMLDeleteTrainedModelAliasFunc(t),
+			DeleteTrainedModel:         newMLDeleteTrainedModelFunc(t),
+			EstimateModelMemory:        newMLEstimateModelMemoryFunc(t),
+			EvaluateDataFrame:          newMLEvaluateDataFrameFunc(t),
+			ExplainDataFrameAnalytics:  newMLExplainDataFrameAnalyticsFunc(t),
+			FindFileStructure:          newMLFindFileStructureFunc(t),
+			FlushJob:                   newMLFlushJobFunc(t),
+			Forecast:                   newMLForecastFunc(t),
+			GetBuckets:                 newMLGetBucketsFunc(t),
+			GetCalendarEvents:          newMLGetCalendarEventsFunc(t),
+			GetCalendars:               newMLGetCalendarsFunc(t),
+			GetCategories:              newMLGetCategoriesFunc(t),
+			GetDataFrameAnalytics:      newMLGetDataFrameAnalyticsFunc(t),
+			GetDataFrameAnalyticsStats: newMLGetDataFrameAnalyticsStatsFunc(t),
+			GetDatafeedStats:           newMLGetDatafeedStatsFunc(t),
+			GetDatafeeds:               newMLGetDatafeedsFunc(t),
+			GetFilters:                 newMLGetFiltersFunc(t),
+			GetInfluencers:             newMLGetInfluencersFunc(t),
+			GetJobStats:                newMLGetJobStatsFunc(t),
+			GetJobs:                    newMLGetJobsFunc(t),
+			GetModelSnapshots:          newMLGetModelSnapshotsFunc(t),
+			GetOverallBuckets:          newMLGetOverallBucketsFunc(t),
+			GetRecords:                 newMLGetRecordsFunc(t),
+			GetTrainedModels:           newMLGetTrainedModelsFunc(t),
+			GetTrainedModelsStats:      newMLGetTrainedModelsStatsFunc(t),
+			Info:                       newMLInfoFunc(t),
+			OpenJob:                    newMLOpenJobFunc(t),
+			PostCalendarEvents:         newMLPostCalendarEventsFunc(t),
+			PostData:                   newMLPostDataFunc(t),
+			PreviewDataFrameAnalytics:  newMLPreviewDataFrameAnalyticsFunc(t),
+			PreviewDatafeed:            newMLPreviewDatafeedFunc(t),
+			PutCalendarJob:             newMLPutCalendarJobFunc(t),
+			PutCalendar:                newMLPutCalendarFunc(t),
+			PutDataFrameAnalytics:      newMLPutDataFrameAnalyticsFunc(t),
+			PutDatafeed:                newMLPutDatafeedFunc(t),
+			PutFilter:                  newMLPutFilterFunc(t),
+			PutJob:                     newMLPutJobFunc(t),
+			PutTrainedModelAlias:       newMLPutTrainedModelAliasFunc(t),
+			PutTrainedModel:            newMLPutTrainedModelFunc(t),
+			ResetJob:                   newMLResetJobFunc(t),
+			RevertModelSnapshot:        newMLRevertModelSnapshotFunc(t),
+			SetUpgradeMode:             newMLSetUpgradeModeFunc(t),
+			StartDataFrameAnalytics:    newMLStartDataFrameAnalyticsFunc(t),
+			StartDatafeed:              newMLStartDatafeedFunc(t),
+			StopDataFrameAnalytics:     newMLStopDataFrameAnalyticsFunc(t),
+			StopDatafeed:               newMLStopDatafeedFunc(t),
+			UpdateDataFrameAnalytics:   newMLUpdateDataFrameAnalyticsFunc(t),
+			UpdateDatafeed:             newMLUpdateDatafeedFunc(t),
+			UpdateFilter:               newMLUpdateFilterFunc(t),
+			UpdateJob:                  newMLUpdateJobFunc(t),
+			UpdateModelSnapshot:        newMLUpdateModelSnapshotFunc(t),
+			UpgradeJobSnapshot:         newMLUpgradeJobSnapshotFunc(t),
+			ValidateDetector:           newMLValidateDetectorFunc(t),
+			Validate:                   newMLValidateFunc(t),
+		},
+		Monitoring: &Monitoring{
+			Bulk: newMonitoringBulkFunc(t),
+		},
+		Rollup: &Rollup{
+			DeleteJob:    newRollupDeleteJobFunc(t),
+			GetJobs:      newRollupGetJobsFunc(t),
+			GetCaps:      newRollupGetRollupCapsFunc(t),
+			GetIndexCaps: newRollupGetRollupIndexCapsFunc(t),
+			PutJob:       newRollupPutJobFunc(t),
+			Rollup:       newRollupRollupFunc(t),
+			Search:       newRollupRollupSearchFunc(t),
+			StartJob:     newRollupStartJobFunc(t),
+			StopJob:      newRollupStopJobFunc(t),
+		},
+		Security: &Security{
+			Authenticate:                newSecurityAuthenticateFunc(t),
+			ChangePassword:              newSecurityChangePasswordFunc(t),
+			ClearAPIKeyCache:            newSecurityClearAPIKeyCacheFunc(t),
+			ClearCachedPrivileges:       newSecurityClearCachedPrivilegesFunc(t),
+			ClearCachedRealms:           newSecurityClearCachedRealmsFunc(t),
+			ClearCachedRoles:            newSecurityClearCachedRolesFunc(t),
+			ClearCachedServiceTokens:    newSecurityClearCachedServiceTokensFunc(t),
+			CreateAPIKey:                newSecurityCreateAPIKeyFunc(t),
+			CreateServiceToken:          newSecurityCreateServiceTokenFunc(t),
+			DeletePrivileges:            newSecurityDeletePrivilegesFunc(t),
+			DeleteRoleMapping:           newSecurityDeleteRoleMappingFunc(t),
+			DeleteRole:                  newSecurityDeleteRoleFunc(t),
+			DeleteServiceToken:          newSecurityDeleteServiceTokenFunc(t),
+			DeleteUser:                  newSecurityDeleteUserFunc(t),
+			DisableUser:                 newSecurityDisableUserFunc(t),
+			EnableUser:                  newSecurityEnableUserFunc(t),
+			GetAPIKey:                   newSecurityGetAPIKeyFunc(t),
+			GetBuiltinPrivileges:        newSecurityGetBuiltinPrivilegesFunc(t),
+			GetPrivileges:               newSecurityGetPrivilegesFunc(t),
+			GetRoleMapping:              newSecurityGetRoleMappingFunc(t),
+			GetRole:                     newSecurityGetRoleFunc(t),
+			GetServiceAccounts:          newSecurityGetServiceAccountsFunc(t),
+			GetServiceCredentials:       newSecurityGetServiceCredentialsFunc(t),
+			GetToken:                    newSecurityGetTokenFunc(t),
+			GetUserPrivileges:           newSecurityGetUserPrivilegesFunc(t),
+			GetUser:                     newSecurityGetUserFunc(t),
+			GrantAPIKey:                 newSecurityGrantAPIKeyFunc(t),
+			HasPrivileges:               newSecurityHasPrivilegesFunc(t),
+			InvalidateAPIKey:            newSecurityInvalidateAPIKeyFunc(t),
+			InvalidateToken:             newSecurityInvalidateTokenFunc(t),
+			PutPrivileges:               newSecurityPutPrivilegesFunc(t),
+			PutRoleMapping:              newSecurityPutRoleMappingFunc(t),
+			PutRole:                     newSecurityPutRoleFunc(t),
+			PutUser:                     newSecurityPutUserFunc(t),
+			QueryAPIKeys:                newSecurityQueryAPIKeysFunc(t),
+			SamlAuthenticate:            newSecuritySamlAuthenticateFunc(t),
+			SamlCompleteLogout:          newSecuritySamlCompleteLogoutFunc(t),
+			SamlInvalidate:              newSecuritySamlInvalidateFunc(t),
+			SamlLogout:                  newSecuritySamlLogoutFunc(t),
+			SamlPrepareAuthentication:   newSecuritySamlPrepareAuthenticationFunc(t),
+			SamlServiceProviderMetadata: newSecuritySamlServiceProviderMetadataFunc(t),
+		},
+		SQL: &SQL{
+			ClearCursor:    newSQLClearCursorFunc(t),
+			DeleteAsync:    newSQLDeleteAsyncFunc(t),
+			GetAsync:       newSQLGetAsyncFunc(t),
+			GetAsyncStatus: newSQLGetAsyncStatusFunc(t),
+			Query:          newSQLQueryFunc(t),
+			Translate:      newSQLTranslateFunc(t),
+		},
+		SSL: &SSL{
+			Certificates: newSSLCertificatesFunc(t),
+		},
+		Watcher: &Watcher{
+			AckWatch:        newWatcherAckWatchFunc(t),
+			ActivateWatch:   newWatcherActivateWatchFunc(t),
+			DeactivateWatch: newWatcherDeactivateWatchFunc(t),
+			DeleteWatch:     newWatcherDeleteWatchFunc(t),
+			ExecuteWatch:    newWatcherExecuteWatchFunc(t),
+			GetWatch:        newWatcherGetWatchFunc(t),
+			PutWatch:        newWatcherPutWatchFunc(t),
+			QueryWatches:    newWatcherQueryWatchesFunc(t),
+			Start:           newWatcherStartFunc(t),
+			Stats:           newWatcherStatsFunc(t),
+			Stop:            newWatcherStopFunc(t),
+		},
+		XPack: &XPack{
+			Info:  newXPackInfoFunc(t),
+			Usage: newXPackUsageFunc(t),
+		},
 	}
 }
diff --git a/esapi/api.bulk.go b/esapi/api.bulk.go
old mode 100755
new mode 100644
index af8e0ead07..14992c15b2
--- a/esapi/api.bulk.go
+++ b/esapi/api.bulk.go
@@ -1,10 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -23,7 +42,7 @@ func newBulkFunc(t Transport) Bulk {
 
 // Bulk allows to perform multiple index/update/delete operations in a single request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-bulk.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-bulk.html.
 //
 type Bulk func(body io.Reader, o ...func(*BulkRequest)) (*Response, error)
 
@@ -32,10 +51,12 @@ type Bulk func(body io.Reader, o ...func(*BulkRequest)) (*Response, error)
 type BulkRequest struct {
 	Index        string
 	DocumentType string
-	Body         io.Reader
+
+	Body io.Reader
 
 	Pipeline            string
 	Refresh             string
+	RequireAlias        *bool
 	Routing             string
 	Source              []string
 	SourceExcludes      []string
@@ -48,6 +69,8 @@ type BulkRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -84,6 +107,10 @@ func (r BulkRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params["refresh"] = r.Refresh
 	}
 
+	if r.RequireAlias != nil {
+		params["require_alias"] = strconv.FormatBool(*r.RequireAlias)
+	}
+
 	if r.Routing != "" {
 		params["routing"] = r.Routing
 	}
@@ -128,7 +155,10 @@ func (r BulkRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -142,6 +172,18 @@ func (r BulkRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -192,7 +234,7 @@ func (f Bulk) WithPipeline(v string) func(*BulkRequest) {
 	}
 }
 
-// WithRefresh - if `true` then refresh the effected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
+// WithRefresh - if `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
 //
 func (f Bulk) WithRefresh(v string) func(*BulkRequest) {
 	return func(r *BulkRequest) {
@@ -200,6 +242,14 @@ func (f Bulk) WithRefresh(v string) func(*BulkRequest) {
 	}
 }
 
+// WithRequireAlias - sets require_alias for all incoming documents. defaults to unset (false).
+//
+func (f Bulk) WithRequireAlias(v bool) func(*BulkRequest) {
+	return func(r *BulkRequest) {
+		r.RequireAlias = &v
+	}
+}
+
 // WithRouting - specific routing value.
 //
 func (f Bulk) WithRouting(v string) func(*BulkRequest) {
@@ -279,3 +329,27 @@ func (f Bulk) WithFilterPath(v ...string) func(*BulkRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Bulk) WithHeader(h map[string]string) func(*BulkRequest) {
+	return func(r *BulkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Bulk) WithOpaqueID(s string) func(*BulkRequest) {
+	return func(r *BulkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.aliases.go b/esapi/api.cat.aliases.go
old mode 100755
new mode 100644
index 4b959e642b..e27d407346
--- a/esapi/api.cat.aliases.go
+++ b/esapi/api.cat.aliases.go
@@ -1,12 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 func newCatAliasesFunc(t Transport) CatAliases {
@@ -23,27 +40,30 @@ func newCatAliasesFunc(t Transport) CatAliases {
 
 // CatAliases shows information about currently configured aliases to indices including filter and routing infos.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-alias.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-alias.html.
 //
 type CatAliases func(o ...func(*CatAliasesRequest)) (*Response, error)
 
 // CatAliasesRequest configures the Cat Aliases API request.
 //
 type CatAliasesRequest struct {
-	Name          []string
-	Format        string
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	Name []string
+
+	ExpandWildcards string
+	Format          string
+	H               []string
+	Help            *bool
+	Local           *bool
+	S               []string
+	V               *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -70,6 +90,10 @@ func (r CatAliasesRequest) Do(ctx context.Context, transport Transport) (*Respon
 
 	params = make(map[string]string)
 
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
 	if r.Format != "" {
 		params["format"] = r.Format
 	}
@@ -86,10 +110,6 @@ func (r CatAliasesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["local"] = strconv.FormatBool(*r.Local)
 	}
 
-	if r.MasterTimeout != 0 {
-		params["master_timeout"] = formatDuration(r.MasterTimeout)
-	}
-
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
@@ -114,7 +134,10 @@ func (r CatAliasesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -124,6 +147,18 @@ func (r CatAliasesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -158,6 +193,14 @@ func (f CatAliases) WithName(v ...string) func(*CatAliasesRequest) {
 	}
 }
 
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f CatAliases) WithExpandWildcards(v string) func(*CatAliasesRequest) {
+	return func(r *CatAliasesRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
 // WithFormat - a short version of the accept header, e.g. json, yaml.
 //
 func (f CatAliases) WithFormat(v string) func(*CatAliasesRequest) {
@@ -190,14 +233,6 @@ func (f CatAliases) WithLocal(v bool) func(*CatAliasesRequest) {
 	}
 }
 
-// WithMasterTimeout - explicit operation timeout for connection to master node.
-//
-func (f CatAliases) WithMasterTimeout(v time.Duration) func(*CatAliasesRequest) {
-	return func(r *CatAliasesRequest) {
-		r.MasterTimeout = v
-	}
-}
-
 // WithS - comma-separated list of column names or column aliases to sort by.
 //
 func (f CatAliases) WithS(v ...string) func(*CatAliasesRequest) {
@@ -245,3 +280,27 @@ func (f CatAliases) WithFilterPath(v ...string) func(*CatAliasesRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatAliases) WithHeader(h map[string]string) func(*CatAliasesRequest) {
+	return func(r *CatAliasesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatAliases) WithOpaqueID(s string) func(*CatAliasesRequest) {
+	return func(r *CatAliasesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.allocation.go b/esapi/api.cat.allocation.go
old mode 100755
new mode 100644
index 1425c31c60..3f56a5ca72
--- a/esapi/api.cat.allocation.go
+++ b/esapi/api.cat.allocation.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newCatAllocationFunc(t Transport) CatAllocation {
 
 // CatAllocation provides a snapshot of how many shards are allocated to each data node and how much disk space they are using.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-allocation.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-allocation.html.
 //
 type CatAllocation func(o ...func(*CatAllocationRequest)) (*Response, error)
 
 // CatAllocationRequest configures the Cat Allocation API request.
 //
 type CatAllocationRequest struct {
-	NodeID        []string
+	NodeID []string
+
 	Bytes         string
 	Format        string
 	H             []string
@@ -45,6 +64,8 @@ type CatAllocationRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -119,7 +140,10 @@ func (r CatAllocationRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -129,6 +153,18 @@ func (r CatAllocationRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -258,3 +294,27 @@ func (f CatAllocation) WithFilterPath(v ...string) func(*CatAllocationRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatAllocation) WithHeader(h map[string]string) func(*CatAllocationRequest) {
+	return func(r *CatAllocationRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatAllocation) WithOpaqueID(s string) func(*CatAllocationRequest) {
+	return func(r *CatAllocationRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.count.go b/esapi/api.cat.count.go
old mode 100755
new mode 100644
index e16d084ece..dab1a04e01
--- a/esapi/api.cat.count.go
+++ b/esapi/api.cat.count.go
@@ -1,12 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 func newCatCountFunc(t Transport) CatCount {
@@ -23,7 +40,7 @@ func newCatCountFunc(t Transport) CatCount {
 
 // CatCount provides quick access to the document count of the entire cluster, or individual indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-count.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-count.html.
 //
 type CatCount func(o ...func(*CatCountRequest)) (*Response, error)
 
@@ -32,19 +49,19 @@ type CatCount func(o ...func(*CatCountRequest)) (*Response, error)
 type CatCountRequest struct {
 	Index []string
 
-	Format        string
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	Format string
+	H      []string
+	Help   *bool
+	S      []string
+	V      *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -83,14 +100,6 @@ func (r CatCountRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
-	if r.Local != nil {
-		params["local"] = strconv.FormatBool(*r.Local)
-	}
-
-	if r.MasterTimeout != 0 {
-		params["master_timeout"] = formatDuration(r.MasterTimeout)
-	}
-
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
@@ -115,7 +124,10 @@ func (r CatCountRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -125,6 +137,18 @@ func (r CatCountRequest) Do(ctx context.Context, transport Transport) (*Response
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -183,22 +207,6 @@ func (f CatCount) WithHelp(v bool) func(*CatCountRequest) {
 	}
 }
 
-// WithLocal - return local information, do not retrieve the state from master node (default: false).
-//
-func (f CatCount) WithLocal(v bool) func(*CatCountRequest) {
-	return func(r *CatCountRequest) {
-		r.Local = &v
-	}
-}
-
-// WithMasterTimeout - explicit operation timeout for connection to master node.
-//
-func (f CatCount) WithMasterTimeout(v time.Duration) func(*CatCountRequest) {
-	return func(r *CatCountRequest) {
-		r.MasterTimeout = v
-	}
-}
-
 // WithS - comma-separated list of column names or column aliases to sort by.
 //
 func (f CatCount) WithS(v ...string) func(*CatCountRequest) {
@@ -246,3 +254,27 @@ func (f CatCount) WithFilterPath(v ...string) func(*CatCountRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatCount) WithHeader(h map[string]string) func(*CatCountRequest) {
+	return func(r *CatCountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatCount) WithOpaqueID(s string) func(*CatCountRequest) {
+	return func(r *CatCountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.fielddata.go b/esapi/api.cat.fielddata.go
old mode 100755
new mode 100644
index f1512a8edb..ee62cdcfa7
--- a/esapi/api.cat.fielddata.go
+++ b/esapi/api.cat.fielddata.go
@@ -1,12 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 func newCatFielddataFunc(t Transport) CatFielddata {
@@ -23,28 +40,29 @@ func newCatFielddataFunc(t Transport) CatFielddata {
 
 // CatFielddata shows how much heap memory is currently being used by fielddata on every data node in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-fielddata.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-fielddata.html.
 //
 type CatFielddata func(o ...func(*CatFielddataRequest)) (*Response, error)
 
 // CatFielddataRequest configures the Cat Fielddata API request.
 //
 type CatFielddataRequest struct {
-	Fields        []string
-	Bytes         string
-	Format        string
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	Fields []string
+
+	Bytes  string
+	Format string
+	H      []string
+	Help   *bool
+	S      []string
+	V      *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -91,14 +109,6 @@ func (r CatFielddataRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
-	if r.Local != nil {
-		params["local"] = strconv.FormatBool(*r.Local)
-	}
-
-	if r.MasterTimeout != 0 {
-		params["master_timeout"] = formatDuration(r.MasterTimeout)
-	}
-
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
@@ -123,7 +133,10 @@ func (r CatFielddataRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -133,6 +146,18 @@ func (r CatFielddataRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -199,22 +224,6 @@ func (f CatFielddata) WithHelp(v bool) func(*CatFielddataRequest) {
 	}
 }
 
-// WithLocal - return local information, do not retrieve the state from master node (default: false).
-//
-func (f CatFielddata) WithLocal(v bool) func(*CatFielddataRequest) {
-	return func(r *CatFielddataRequest) {
-		r.Local = &v
-	}
-}
-
-// WithMasterTimeout - explicit operation timeout for connection to master node.
-//
-func (f CatFielddata) WithMasterTimeout(v time.Duration) func(*CatFielddataRequest) {
-	return func(r *CatFielddataRequest) {
-		r.MasterTimeout = v
-	}
-}
-
 // WithS - comma-separated list of column names or column aliases to sort by.
 //
 func (f CatFielddata) WithS(v ...string) func(*CatFielddataRequest) {
@@ -262,3 +271,27 @@ func (f CatFielddata) WithFilterPath(v ...string) func(*CatFielddataRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatFielddata) WithHeader(h map[string]string) func(*CatFielddataRequest) {
+	return func(r *CatFielddataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatFielddata) WithOpaqueID(s string) func(*CatFielddataRequest) {
+	return func(r *CatFielddataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.health.go b/esapi/api.cat.health.go
old mode 100755
new mode 100644
index 6c9dea466c..e4bc0e8ce8
--- a/esapi/api.cat.health.go
+++ b/esapi/api.cat.health.go
@@ -1,12 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 func newCatHealthFunc(t Transport) CatHealth {
@@ -23,27 +40,28 @@ func newCatHealthFunc(t Transport) CatHealth {
 
 // CatHealth returns a concise representation of the cluster health.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-health.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-health.html.
 //
 type CatHealth func(o ...func(*CatHealthRequest)) (*Response, error)
 
 // CatHealthRequest configures the Cat Health API request.
 //
 type CatHealthRequest struct {
-	Format        string
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	Ts            *bool
-	V             *bool
+	Format string
+	H      []string
+	Help   *bool
+	S      []string
+	Time   string
+	Ts     *bool
+	V      *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -75,18 +93,14 @@ func (r CatHealthRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
-	if r.Local != nil {
-		params["local"] = strconv.FormatBool(*r.Local)
-	}
-
-	if r.MasterTimeout != 0 {
-		params["master_timeout"] = formatDuration(r.MasterTimeout)
-	}
-
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.Ts != nil {
 		params["ts"] = strconv.FormatBool(*r.Ts)
 	}
@@ -111,7 +125,10 @@ func (r CatHealthRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -121,6 +138,18 @@ func (r CatHealthRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -171,27 +200,19 @@ func (f CatHealth) WithHelp(v bool) func(*CatHealthRequest) {
 	}
 }
 
-// WithLocal - return local information, do not retrieve the state from master node (default: false).
-//
-func (f CatHealth) WithLocal(v bool) func(*CatHealthRequest) {
-	return func(r *CatHealthRequest) {
-		r.Local = &v
-	}
-}
-
-// WithMasterTimeout - explicit operation timeout for connection to master node.
+// WithS - comma-separated list of column names or column aliases to sort by.
 //
-func (f CatHealth) WithMasterTimeout(v time.Duration) func(*CatHealthRequest) {
+func (f CatHealth) WithS(v ...string) func(*CatHealthRequest) {
 	return func(r *CatHealthRequest) {
-		r.MasterTimeout = v
+		r.S = v
 	}
 }
 
-// WithS - comma-separated list of column names or column aliases to sort by.
+// WithTime - the unit in which to display time values.
 //
-func (f CatHealth) WithS(v ...string) func(*CatHealthRequest) {
+func (f CatHealth) WithTime(v string) func(*CatHealthRequest) {
 	return func(r *CatHealthRequest) {
-		r.S = v
+		r.Time = v
 	}
 }
 
@@ -242,3 +263,27 @@ func (f CatHealth) WithFilterPath(v ...string) func(*CatHealthRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatHealth) WithHeader(h map[string]string) func(*CatHealthRequest) {
+	return func(r *CatHealthRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatHealth) WithOpaqueID(s string) func(*CatHealthRequest) {
+	return func(r *CatHealthRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.help.go b/esapi/api.cat.help.go
old mode 100755
new mode 100644
index 042aa14266..0880018c5c
--- a/esapi/api.cat.help.go
+++ b/esapi/api.cat.help.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newCatHelpFunc(t Transport) CatHelp {
 
 // CatHelp returns help for the Cat APIs.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat.html.
 //
 type CatHelp func(o ...func(*CatHelpRequest)) (*Response, error)
 
@@ -37,6 +55,8 @@ type CatHelpRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -80,7 +100,10 @@ func (r CatHelpRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -90,6 +113,18 @@ func (r CatHelpRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -163,3 +198,27 @@ func (f CatHelp) WithFilterPath(v ...string) func(*CatHelpRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatHelp) WithHeader(h map[string]string) func(*CatHelpRequest) {
+	return func(r *CatHelpRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatHelp) WithOpaqueID(s string) func(*CatHelpRequest) {
+	return func(r *CatHelpRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.indices.go b/esapi/api.cat.indices.go
old mode 100755
new mode 100644
index 80876b06a0..d1408d4a89
--- a/esapi/api.cat.indices.go
+++ b/esapi/api.cat.indices.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newCatIndicesFunc(t Transport) CatIndices {
 
 // CatIndices returns information about indices: number of primaries and replicas, document counts, disk size, ...
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-indices.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-indices.html.
 //
 type CatIndices func(o ...func(*CatIndicesRequest)) (*Response, error)
 
@@ -32,22 +50,27 @@ type CatIndices func(o ...func(*CatIndicesRequest)) (*Response, error)
 type CatIndicesRequest struct {
 	Index []string
 
-	Bytes         string
-	Format        string
-	H             []string
-	Health        string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	Pri           *bool
-	S             []string
-	V             *bool
+	Bytes                   string
+	ExpandWildcards         string
+	Format                  string
+	H                       []string
+	Health                  string
+	Help                    *bool
+	IncludeUnloadedSegments *bool
+	Local                   *bool
+	MasterTimeout           time.Duration
+	Pri                     *bool
+	S                       []string
+	Time                    string
+	V                       *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -78,6 +101,10 @@ func (r CatIndicesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["bytes"] = r.Bytes
 	}
 
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
 	if r.Format != "" {
 		params["format"] = r.Format
 	}
@@ -94,6 +121,10 @@ func (r CatIndicesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
+	if r.IncludeUnloadedSegments != nil {
+		params["include_unloaded_segments"] = strconv.FormatBool(*r.IncludeUnloadedSegments)
+	}
+
 	if r.Local != nil {
 		params["local"] = strconv.FormatBool(*r.Local)
 	}
@@ -110,6 +141,10 @@ func (r CatIndicesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -130,7 +165,10 @@ func (r CatIndicesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -140,6 +178,18 @@ func (r CatIndicesRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -182,6 +232,14 @@ func (f CatIndices) WithBytes(v string) func(*CatIndicesRequest) {
 	}
 }
 
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f CatIndices) WithExpandWildcards(v string) func(*CatIndicesRequest) {
+	return func(r *CatIndicesRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
 // WithFormat - a short version of the accept header, e.g. json, yaml.
 //
 func (f CatIndices) WithFormat(v string) func(*CatIndicesRequest) {
@@ -214,6 +272,14 @@ func (f CatIndices) WithHelp(v bool) func(*CatIndicesRequest) {
 	}
 }
 
+// WithIncludeUnloadedSegments - if set to true segment stats will include stats for segments that are not currently loaded into memory.
+//
+func (f CatIndices) WithIncludeUnloadedSegments(v bool) func(*CatIndicesRequest) {
+	return func(r *CatIndicesRequest) {
+		r.IncludeUnloadedSegments = &v
+	}
+}
+
 // WithLocal - return local information, do not retrieve the state from master node (default: false).
 //
 func (f CatIndices) WithLocal(v bool) func(*CatIndicesRequest) {
@@ -246,6 +312,14 @@ func (f CatIndices) WithS(v ...string) func(*CatIndicesRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatIndices) WithTime(v string) func(*CatIndicesRequest) {
+	return func(r *CatIndicesRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatIndices) WithV(v bool) func(*CatIndicesRequest) {
@@ -285,3 +359,27 @@ func (f CatIndices) WithFilterPath(v ...string) func(*CatIndicesRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatIndices) WithHeader(h map[string]string) func(*CatIndicesRequest) {
+	return func(r *CatIndicesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatIndices) WithOpaqueID(s string) func(*CatIndicesRequest) {
+	return func(r *CatIndicesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.master.go b/esapi/api.cat.master.go
old mode 100755
new mode 100644
index 10a9e0ab66..777277a1ad
--- a/esapi/api.cat.master.go
+++ b/esapi/api.cat.master.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newCatMasterFunc(t Transport) CatMaster {
 
 // CatMaster returns information about the master node.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-master.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-master.html.
 //
 type CatMaster func(o ...func(*CatMasterRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type CatMasterRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -106,7 +126,10 @@ func (r CatMasterRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +139,18 @@ func (r CatMasterRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -229,3 +264,27 @@ func (f CatMaster) WithFilterPath(v ...string) func(*CatMasterRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatMaster) WithHeader(h map[string]string) func(*CatMasterRequest) {
+	return func(r *CatMasterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatMaster) WithOpaqueID(s string) func(*CatMasterRequest) {
+	return func(r *CatMasterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.nodeattrs.go b/esapi/api.cat.nodeattrs.go
old mode 100755
new mode 100644
index 3b35c71737..8c09f22bab
--- a/esapi/api.cat.nodeattrs.go
+++ b/esapi/api.cat.nodeattrs.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newCatNodeattrsFunc(t Transport) CatNodeattrs {
 
 // CatNodeattrs returns information about custom node attributes.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodeattrs.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodeattrs.html.
 //
 type CatNodeattrs func(o ...func(*CatNodeattrsRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type CatNodeattrsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -106,7 +126,10 @@ func (r CatNodeattrsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +139,18 @@ func (r CatNodeattrsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -229,3 +264,27 @@ func (f CatNodeattrs) WithFilterPath(v ...string) func(*CatNodeattrsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatNodeattrs) WithHeader(h map[string]string) func(*CatNodeattrsRequest) {
+	return func(r *CatNodeattrsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatNodeattrs) WithOpaqueID(s string) func(*CatNodeattrsRequest) {
+	return func(r *CatNodeattrsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.nodes.go b/esapi/api.cat.nodes.go
old mode 100755
new mode 100644
index 8cea2f9b22..2a10848557
--- a/esapi/api.cat.nodes.go
+++ b/esapi/api.cat.nodes.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,27 +41,32 @@ func newCatNodesFunc(t Transport) CatNodes {
 
 // CatNodes returns basic statistics about performance of cluster nodes.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodes.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodes.html.
 //
 type CatNodes func(o ...func(*CatNodesRequest)) (*Response, error)
 
 // CatNodesRequest configures the Cat Nodes API request.
 //
 type CatNodesRequest struct {
-	Format        string
-	FullID        *bool
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	Bytes                   string
+	Format                  string
+	FullID                  *bool
+	H                       []string
+	Help                    *bool
+	IncludeUnloadedSegments *bool
+	Local                   *bool
+	MasterTimeout           time.Duration
+	S                       []string
+	Time                    string
+	V                       *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -63,6 +86,10 @@ func (r CatNodesRequest) Do(ctx context.Context, transport Transport) (*Response
 
 	params = make(map[string]string)
 
+	if r.Bytes != "" {
+		params["bytes"] = r.Bytes
+	}
+
 	if r.Format != "" {
 		params["format"] = r.Format
 	}
@@ -79,6 +106,10 @@ func (r CatNodesRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
+	if r.IncludeUnloadedSegments != nil {
+		params["include_unloaded_segments"] = strconv.FormatBool(*r.IncludeUnloadedSegments)
+	}
+
 	if r.Local != nil {
 		params["local"] = strconv.FormatBool(*r.Local)
 	}
@@ -91,6 +122,10 @@ func (r CatNodesRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -111,7 +146,10 @@ func (r CatNodesRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -121,6 +159,18 @@ func (r CatNodesRequest) Do(ctx context.Context, transport Transport) (*Response
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -147,6 +197,14 @@ func (f CatNodes) WithContext(v context.Context) func(*CatNodesRequest) {
 	}
 }
 
+// WithBytes - the unit in which to display byte values.
+//
+func (f CatNodes) WithBytes(v string) func(*CatNodesRequest) {
+	return func(r *CatNodesRequest) {
+		r.Bytes = v
+	}
+}
+
 // WithFormat - a short version of the accept header, e.g. json, yaml.
 //
 func (f CatNodes) WithFormat(v string) func(*CatNodesRequest) {
@@ -179,7 +237,15 @@ func (f CatNodes) WithHelp(v bool) func(*CatNodesRequest) {
 	}
 }
 
-// WithLocal - return local information, do not retrieve the state from master node (default: false).
+// WithIncludeUnloadedSegments - if set to true segment stats will include stats for segments that are not currently loaded into memory.
+//
+func (f CatNodes) WithIncludeUnloadedSegments(v bool) func(*CatNodesRequest) {
+	return func(r *CatNodesRequest) {
+		r.IncludeUnloadedSegments = &v
+	}
+}
+
+// WithLocal - calculate the selected nodes using the local cluster state rather than the state from master node (default: false).
 //
 func (f CatNodes) WithLocal(v bool) func(*CatNodesRequest) {
 	return func(r *CatNodesRequest) {
@@ -203,6 +269,14 @@ func (f CatNodes) WithS(v ...string) func(*CatNodesRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatNodes) WithTime(v string) func(*CatNodesRequest) {
+	return func(r *CatNodesRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatNodes) WithV(v bool) func(*CatNodesRequest) {
@@ -242,3 +316,27 @@ func (f CatNodes) WithFilterPath(v ...string) func(*CatNodesRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatNodes) WithHeader(h map[string]string) func(*CatNodesRequest) {
+	return func(r *CatNodesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatNodes) WithOpaqueID(s string) func(*CatNodesRequest) {
+	return func(r *CatNodesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.pending_tasks.go b/esapi/api.cat.pending_tasks.go
old mode 100755
new mode 100644
index 2ee059c048..5f5d7a9f50
--- a/esapi/api.cat.pending_tasks.go
+++ b/esapi/api.cat.pending_tasks.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,11 +41,11 @@ func newCatPendingTasksFunc(t Transport) CatPendingTasks {
 
 // CatPendingTasks returns a concise representation of the cluster pending tasks.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-pending-tasks.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-pending-tasks.html.
 //
 type CatPendingTasks func(o ...func(*CatPendingTasksRequest)) (*Response, error)
 
-// CatPendingTasksRequest configures the Cat  Pending Tasks API request.
+// CatPendingTasksRequest configures the Cat Pending Tasks API request.
 //
 type CatPendingTasksRequest struct {
 	Format        string
@@ -36,6 +54,7 @@ type CatPendingTasksRequest struct {
 	Local         *bool
 	MasterTimeout time.Duration
 	S             []string
+	Time          string
 	V             *bool
 
 	Pretty     bool
@@ -43,6 +62,8 @@ type CatPendingTasksRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -86,6 +107,10 @@ func (r CatPendingTasksRequest) Do(ctx context.Context, transport Transport) (*R
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -106,7 +131,10 @@ func (r CatPendingTasksRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +144,18 @@ func (r CatPendingTasksRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -190,6 +230,14 @@ func (f CatPendingTasks) WithS(v ...string) func(*CatPendingTasksRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatPendingTasks) WithTime(v string) func(*CatPendingTasksRequest) {
+	return func(r *CatPendingTasksRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatPendingTasks) WithV(v bool) func(*CatPendingTasksRequest) {
@@ -229,3 +277,27 @@ func (f CatPendingTasks) WithFilterPath(v ...string) func(*CatPendingTasksReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatPendingTasks) WithHeader(h map[string]string) func(*CatPendingTasksRequest) {
+	return func(r *CatPendingTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatPendingTasks) WithOpaqueID(s string) func(*CatPendingTasksRequest) {
+	return func(r *CatPendingTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.plugins.go b/esapi/api.cat.plugins.go
old mode 100755
new mode 100644
index b4c7f37809..82e26d18cf
--- a/esapi/api.cat.plugins.go
+++ b/esapi/api.cat.plugins.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,26 +41,29 @@ func newCatPluginsFunc(t Transport) CatPlugins {
 
 // CatPlugins returns information about installed plugins across nodes node.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-plugins.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-plugins.html.
 //
 type CatPlugins func(o ...func(*CatPluginsRequest)) (*Response, error)
 
 // CatPluginsRequest configures the Cat Plugins API request.
 //
 type CatPluginsRequest struct {
-	Format        string
-	H             []string
-	Help          *bool
-	Local         *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	Format           string
+	H                []string
+	Help             *bool
+	IncludeBootstrap *bool
+	Local            *bool
+	MasterTimeout    time.Duration
+	S                []string
+	V                *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -74,6 +95,10 @@ func (r CatPluginsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
+	if r.IncludeBootstrap != nil {
+		params["include_bootstrap"] = strconv.FormatBool(*r.IncludeBootstrap)
+	}
+
 	if r.Local != nil {
 		params["local"] = strconv.FormatBool(*r.Local)
 	}
@@ -106,7 +131,10 @@ func (r CatPluginsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +144,18 @@ func (r CatPluginsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -166,6 +206,14 @@ func (f CatPlugins) WithHelp(v bool) func(*CatPluginsRequest) {
 	}
 }
 
+// WithIncludeBootstrap - include bootstrap plugins in the response.
+//
+func (f CatPlugins) WithIncludeBootstrap(v bool) func(*CatPluginsRequest) {
+	return func(r *CatPluginsRequest) {
+		r.IncludeBootstrap = &v
+	}
+}
+
 // WithLocal - return local information, do not retrieve the state from master node (default: false).
 //
 func (f CatPlugins) WithLocal(v bool) func(*CatPluginsRequest) {
@@ -229,3 +277,27 @@ func (f CatPlugins) WithFilterPath(v ...string) func(*CatPluginsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatPlugins) WithHeader(h map[string]string) func(*CatPluginsRequest) {
+	return func(r *CatPluginsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatPlugins) WithOpaqueID(s string) func(*CatPluginsRequest) {
+	return func(r *CatPluginsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.recovery.go b/esapi/api.cat.recovery.go
old mode 100755
new mode 100644
index 5abfafef1b..38c5b78583
--- a/esapi/api.cat.recovery.go
+++ b/esapi/api.cat.recovery.go
@@ -1,12 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 func newCatRecoveryFunc(t Transport) CatRecovery {
@@ -23,7 +40,7 @@ func newCatRecoveryFunc(t Transport) CatRecovery {
 
 // CatRecovery returns information about index shard recoveries, both on-going completed.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-recovery.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-recovery.html.
 //
 type CatRecovery func(o ...func(*CatRecoveryRequest)) (*Response, error)
 
@@ -32,19 +49,23 @@ type CatRecovery func(o ...func(*CatRecoveryRequest)) (*Response, error)
 type CatRecoveryRequest struct {
 	Index []string
 
-	Bytes         string
-	Format        string
-	H             []string
-	Help          *bool
-	MasterTimeout time.Duration
-	S             []string
-	V             *bool
+	ActiveOnly *bool
+	Bytes      string
+	Detailed   *bool
+	Format     string
+	H          []string
+	Help       *bool
+	S          []string
+	Time       string
+	V          *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -71,10 +92,18 @@ func (r CatRecoveryRequest) Do(ctx context.Context, transport Transport) (*Respo
 
 	params = make(map[string]string)
 
+	if r.ActiveOnly != nil {
+		params["active_only"] = strconv.FormatBool(*r.ActiveOnly)
+	}
+
 	if r.Bytes != "" {
 		params["bytes"] = r.Bytes
 	}
 
+	if r.Detailed != nil {
+		params["detailed"] = strconv.FormatBool(*r.Detailed)
+	}
+
 	if r.Format != "" {
 		params["format"] = r.Format
 	}
@@ -87,14 +116,18 @@ func (r CatRecoveryRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
-	if r.MasterTimeout != 0 {
-		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	if len(r.Index) > 0 {
+		params["index"] = strings.Join(r.Index, ",")
 	}
 
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -115,7 +148,10 @@ func (r CatRecoveryRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -125,6 +161,18 @@ func (r CatRecoveryRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -151,7 +199,7 @@ func (f CatRecovery) WithContext(v context.Context) func(*CatRecoveryRequest) {
 	}
 }
 
-// WithIndex - a list of index names to limit the returned information.
+// WithIndex - comma-separated list or wildcard expression of index names to limit the returned information.
 //
 func (f CatRecovery) WithIndex(v ...string) func(*CatRecoveryRequest) {
 	return func(r *CatRecoveryRequest) {
@@ -159,6 +207,14 @@ func (f CatRecovery) WithIndex(v ...string) func(*CatRecoveryRequest) {
 	}
 }
 
+// WithActiveOnly - if `true`, the response only includes ongoing shard recoveries.
+//
+func (f CatRecovery) WithActiveOnly(v bool) func(*CatRecoveryRequest) {
+	return func(r *CatRecoveryRequest) {
+		r.ActiveOnly = &v
+	}
+}
+
 // WithBytes - the unit in which to display byte values.
 //
 func (f CatRecovery) WithBytes(v string) func(*CatRecoveryRequest) {
@@ -167,6 +223,14 @@ func (f CatRecovery) WithBytes(v string) func(*CatRecoveryRequest) {
 	}
 }
 
+// WithDetailed - if `true`, the response includes detailed information about shard recoveries.
+//
+func (f CatRecovery) WithDetailed(v bool) func(*CatRecoveryRequest) {
+	return func(r *CatRecoveryRequest) {
+		r.Detailed = &v
+	}
+}
+
 // WithFormat - a short version of the accept header, e.g. json, yaml.
 //
 func (f CatRecovery) WithFormat(v string) func(*CatRecoveryRequest) {
@@ -191,19 +255,19 @@ func (f CatRecovery) WithHelp(v bool) func(*CatRecoveryRequest) {
 	}
 }
 
-// WithMasterTimeout - explicit operation timeout for connection to master node.
+// WithS - comma-separated list of column names or column aliases to sort by.
 //
-func (f CatRecovery) WithMasterTimeout(v time.Duration) func(*CatRecoveryRequest) {
+func (f CatRecovery) WithS(v ...string) func(*CatRecoveryRequest) {
 	return func(r *CatRecoveryRequest) {
-		r.MasterTimeout = v
+		r.S = v
 	}
 }
 
-// WithS - comma-separated list of column names or column aliases to sort by.
+// WithTime - the unit in which to display time values.
 //
-func (f CatRecovery) WithS(v ...string) func(*CatRecoveryRequest) {
+func (f CatRecovery) WithTime(v string) func(*CatRecoveryRequest) {
 	return func(r *CatRecoveryRequest) {
-		r.S = v
+		r.Time = v
 	}
 }
 
@@ -246,3 +310,27 @@ func (f CatRecovery) WithFilterPath(v ...string) func(*CatRecoveryRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatRecovery) WithHeader(h map[string]string) func(*CatRecoveryRequest) {
+	return func(r *CatRecoveryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatRecovery) WithOpaqueID(s string) func(*CatRecoveryRequest) {
+	return func(r *CatRecoveryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.repositories.go b/esapi/api.cat.repositories.go
old mode 100755
new mode 100644
index 10ac6e330d..5e5c56ae52
--- a/esapi/api.cat.repositories.go
+++ b/esapi/api.cat.repositories.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newCatRepositoriesFunc(t Transport) CatRepositories {
 
 // CatRepositories returns information about snapshot repositories registered in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-repositories.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-repositories.html.
 //
 type CatRepositories func(o ...func(*CatRepositoriesRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type CatRepositoriesRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -106,7 +126,10 @@ func (r CatRepositoriesRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +139,18 @@ func (r CatRepositoriesRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -229,3 +264,27 @@ func (f CatRepositories) WithFilterPath(v ...string) func(*CatRepositoriesReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatRepositories) WithHeader(h map[string]string) func(*CatRepositoriesRequest) {
+	return func(r *CatRepositoriesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatRepositories) WithOpaqueID(s string) func(*CatRepositoriesRequest) {
+	return func(r *CatRepositoriesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.segments.go b/esapi/api.cat.segments.go
old mode 100755
new mode 100644
index 255fb8ff4c..2c5f5ef960
--- a/esapi/api.cat.segments.go
+++ b/esapi/api.cat.segments.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newCatSegmentsFunc(t Transport) CatSegments {
 
 // CatSegments provides low-level information about the segments in the shards of an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-segments.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-segments.html.
 //
 type CatSegments func(o ...func(*CatSegmentsRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type CatSegmentsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -109,7 +129,10 @@ func (r CatSegmentsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -119,6 +142,18 @@ func (r CatSegmentsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -232,3 +267,27 @@ func (f CatSegments) WithFilterPath(v ...string) func(*CatSegmentsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatSegments) WithHeader(h map[string]string) func(*CatSegmentsRequest) {
+	return func(r *CatSegmentsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatSegments) WithOpaqueID(s string) func(*CatSegmentsRequest) {
+	return func(r *CatSegmentsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.shards.go b/esapi/api.cat.shards.go
old mode 100755
new mode 100644
index c96c852a22..add5d1e28e
--- a/esapi/api.cat.shards.go
+++ b/esapi/api.cat.shards.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newCatShardsFunc(t Transport) CatShards {
 
 // CatShards provides a detailed view of shard allocation on nodes.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-shards.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-shards.html.
 //
 type CatShards func(o ...func(*CatShardsRequest)) (*Response, error)
 
@@ -39,6 +57,7 @@ type CatShardsRequest struct {
 	Local         *bool
 	MasterTimeout time.Duration
 	S             []string
+	Time          string
 	V             *bool
 
 	Pretty     bool
@@ -46,6 +65,8 @@ type CatShardsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -100,6 +121,10 @@ func (r CatShardsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -120,7 +145,10 @@ func (r CatShardsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -130,6 +158,18 @@ func (r CatShardsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -220,6 +260,14 @@ func (f CatShards) WithS(v ...string) func(*CatShardsRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatShards) WithTime(v string) func(*CatShardsRequest) {
+	return func(r *CatShardsRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatShards) WithV(v bool) func(*CatShardsRequest) {
@@ -259,3 +307,27 @@ func (f CatShards) WithFilterPath(v ...string) func(*CatShardsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatShards) WithHeader(h map[string]string) func(*CatShardsRequest) {
+	return func(r *CatShardsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatShards) WithOpaqueID(s string) func(*CatShardsRequest) {
+	return func(r *CatShardsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.snapshots.go b/esapi/api.cat.snapshots.go
old mode 100755
new mode 100644
index 0015364d85..5d75b3d220
--- a/esapi/api.cat.snapshots.go
+++ b/esapi/api.cat.snapshots.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,20 +41,22 @@ func newCatSnapshotsFunc(t Transport) CatSnapshots {
 
 // CatSnapshots returns all snapshots in a specific repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-snapshots.html.
 //
 type CatSnapshots func(o ...func(*CatSnapshotsRequest)) (*Response, error)
 
 // CatSnapshotsRequest configures the Cat Snapshots API request.
 //
 type CatSnapshotsRequest struct {
-	Repository        []string
+	Repository []string
+
 	Format            string
 	H                 []string
 	Help              *bool
 	IgnoreUnavailable *bool
 	MasterTimeout     time.Duration
 	S                 []string
+	Time              string
 	V                 *bool
 
 	Pretty     bool
@@ -44,6 +64,8 @@ type CatSnapshotsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -94,6 +116,10 @@ func (r CatSnapshotsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -114,7 +140,10 @@ func (r CatSnapshotsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -124,6 +153,18 @@ func (r CatSnapshotsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -206,6 +247,14 @@ func (f CatSnapshots) WithS(v ...string) func(*CatSnapshotsRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatSnapshots) WithTime(v string) func(*CatSnapshotsRequest) {
+	return func(r *CatSnapshotsRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatSnapshots) WithV(v bool) func(*CatSnapshotsRequest) {
@@ -245,3 +294,27 @@ func (f CatSnapshots) WithFilterPath(v ...string) func(*CatSnapshotsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatSnapshots) WithHeader(h map[string]string) func(*CatSnapshotsRequest) {
+	return func(r *CatSnapshotsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatSnapshots) WithOpaqueID(s string) func(*CatSnapshotsRequest) {
+	return func(r *CatSnapshotsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.tasks.go b/esapi/api.cat.tasks.go
old mode 100755
new mode 100644
index 933db86044..f384c8707d
--- a/esapi/api.cat.tasks.go
+++ b/esapi/api.cat.tasks.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,28 +40,31 @@ func newCatTasksFunc(t Transport) CatTasks {
 
 // CatTasks returns information about the tasks currently executing on one or more nodes in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
 //
 type CatTasks func(o ...func(*CatTasksRequest)) (*Response, error)
 
 // CatTasksRequest configures the Cat Tasks API request.
 //
 type CatTasksRequest struct {
-	Actions    []string
-	Detailed   *bool
-	Format     string
-	H          []string
-	Help       *bool
-	NodeID     []string
-	ParentTask *int
-	S          []string
-	V          *bool
+	Actions      []string
+	Detailed     *bool
+	Format       string
+	H            []string
+	Help         *bool
+	Nodes        []string
+	ParentTaskID string
+	S            []string
+	Time         string
+	V            *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -83,18 +104,22 @@ func (r CatTasksRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["help"] = strconv.FormatBool(*r.Help)
 	}
 
-	if len(r.NodeID) > 0 {
-		params["node_id"] = strings.Join(r.NodeID, ",")
+	if len(r.Nodes) > 0 {
+		params["nodes"] = strings.Join(r.Nodes, ",")
 	}
 
-	if r.ParentTask != nil {
-		params["parent_task"] = strconv.FormatInt(int64(*r.ParentTask), 10)
+	if r.ParentTaskID != "" {
+		params["parent_task_id"] = r.ParentTaskID
 	}
 
 	if len(r.S) > 0 {
 		params["s"] = strings.Join(r.S, ",")
 	}
 
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
 	if r.V != nil {
 		params["v"] = strconv.FormatBool(*r.V)
 	}
@@ -115,7 +140,10 @@ func (r CatTasksRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -125,6 +153,18 @@ func (r CatTasksRequest) Do(ctx context.Context, transport Transport) (*Response
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,19 +231,19 @@ func (f CatTasks) WithHelp(v bool) func(*CatTasksRequest) {
 	}
 }
 
-// WithNodeID - a list of node ids or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
+// WithNodes - a list of node ids or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
 //
-func (f CatTasks) WithNodeID(v ...string) func(*CatTasksRequest) {
+func (f CatTasks) WithNodes(v ...string) func(*CatTasksRequest) {
 	return func(r *CatTasksRequest) {
-		r.NodeID = v
+		r.Nodes = v
 	}
 }
 
-// WithParentTask - return tasks with specified parent task ID. set to -1 to return all..
+// WithParentTaskID - return tasks with specified parent task ID (node_id:task_number). set to -1 to return all..
 //
-func (f CatTasks) WithParentTask(v int) func(*CatTasksRequest) {
+func (f CatTasks) WithParentTaskID(v string) func(*CatTasksRequest) {
 	return func(r *CatTasksRequest) {
-		r.ParentTask = &v
+		r.ParentTaskID = v
 	}
 }
 
@@ -215,6 +255,14 @@ func (f CatTasks) WithS(v ...string) func(*CatTasksRequest) {
 	}
 }
 
+// WithTime - the unit in which to display time values.
+//
+func (f CatTasks) WithTime(v string) func(*CatTasksRequest) {
+	return func(r *CatTasksRequest) {
+		r.Time = v
+	}
+}
+
 // WithV - verbose mode. display column headers.
 //
 func (f CatTasks) WithV(v bool) func(*CatTasksRequest) {
@@ -254,3 +302,27 @@ func (f CatTasks) WithFilterPath(v ...string) func(*CatTasksRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatTasks) WithHeader(h map[string]string) func(*CatTasksRequest) {
+	return func(r *CatTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatTasks) WithOpaqueID(s string) func(*CatTasksRequest) {
+	return func(r *CatTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.templates.go b/esapi/api.cat.templates.go
old mode 100755
new mode 100644
index f5bc804a49..a4ff1a09fe
--- a/esapi/api.cat.templates.go
+++ b/esapi/api.cat.templates.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newCatTemplatesFunc(t Transport) CatTemplates {
 
 // CatTemplates returns information about existing templates.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-templates.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-templates.html.
 //
 type CatTemplates func(o ...func(*CatTemplatesRequest)) (*Response, error)
 
 // CatTemplatesRequest configures the Cat Templates API request.
 //
 type CatTemplatesRequest struct {
-	Name          string
+	Name string
+
 	Format        string
 	H             []string
 	Help          *bool
@@ -44,6 +63,8 @@ type CatTemplatesRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -114,7 +135,10 @@ func (r CatTemplatesRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -124,6 +148,18 @@ func (r CatTemplatesRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -245,3 +281,27 @@ func (f CatTemplates) WithFilterPath(v ...string) func(*CatTemplatesRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatTemplates) WithHeader(h map[string]string) func(*CatTemplatesRequest) {
+	return func(r *CatTemplatesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatTemplates) WithOpaqueID(s string) func(*CatTemplatesRequest) {
+	return func(r *CatTemplatesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cat.thread_pool.go b/esapi/api.cat.thread_pool.go
old mode 100755
new mode 100644
index 1f501d784c..d27c5c300a
--- a/esapi/api.cat.thread_pool.go
+++ b/esapi/api.cat.thread_pool.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,28 +42,31 @@ func newCatThreadPoolFunc(t Transport) CatThreadPool {
 // CatThreadPool returns cluster-wide thread pool statistics per node.
 // By default the active, queue and rejected statistics are returned for all thread pools.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-thread-pool.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cat-thread-pool.html.
 //
 type CatThreadPool func(o ...func(*CatThreadPoolRequest)) (*Response, error)
 
-// CatThreadPoolRequest configures the Cat  Thread Pool API request.
+// CatThreadPoolRequest configures the Cat Thread Pool API request.
 //
 type CatThreadPoolRequest struct {
 	ThreadPoolPatterns []string
-	Format             string
-	H                  []string
-	Help               *bool
-	Local              *bool
-	MasterTimeout      time.Duration
-	S                  []string
-	Size               string
-	V                  *bool
+
+	Format        string
+	H             []string
+	Help          *bool
+	Local         *bool
+	MasterTimeout time.Duration
+	S             []string
+	Size          string
+	V             *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -120,7 +141,10 @@ func (r CatThreadPoolRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -130,6 +154,18 @@ func (r CatThreadPoolRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -259,3 +295,27 @@ func (f CatThreadPool) WithFilterPath(v ...string) func(*CatThreadPoolRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatThreadPool) WithHeader(h map[string]string) func(*CatThreadPoolRequest) {
+	return func(r *CatThreadPoolRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatThreadPool) WithOpaqueID(s string) func(*CatThreadPoolRequest) {
+	return func(r *CatThreadPoolRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.clear_scroll.go b/esapi/api.clear_scroll.go
old mode 100755
new mode 100644
index 99cedf092b..bcbf92397d
--- a/esapi/api.clear_scroll.go
+++ b/esapi/api.clear_scroll.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 )
 
@@ -22,7 +40,7 @@ func newClearScrollFunc(t Transport) ClearScroll {
 
 // ClearScroll explicitly clears the search context for a scroll.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/clear-scroll-api.html.
 //
 type ClearScroll func(o ...func(*ClearScrollRequest)) (*Response, error)
 
@@ -38,6 +56,8 @@ type ClearScrollRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -80,7 +100,10 @@ func (r ClearScrollRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -94,6 +117,18 @@ func (r ClearScrollRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -120,19 +155,19 @@ func (f ClearScroll) WithContext(v context.Context) func(*ClearScrollRequest) {
 	}
 }
 
-// WithScrollID - a list of scroll ids to clear.
+// WithBody - A comma-separated list of scroll IDs to clear if none was specified via the scroll_id parameter.
 //
-func (f ClearScroll) WithScrollID(v ...string) func(*ClearScrollRequest) {
+func (f ClearScroll) WithBody(v io.Reader) func(*ClearScrollRequest) {
 	return func(r *ClearScrollRequest) {
-		r.ScrollID = v
+		r.Body = v
 	}
 }
 
-// WithBody - A comma-separated list of scroll IDs to clear if none was specified via the scroll_id parameter.
+// WithScrollID - a list of scroll ids to clear.
 //
-func (f ClearScroll) WithBody(v io.Reader) func(*ClearScrollRequest) {
+func (f ClearScroll) WithScrollID(v ...string) func(*ClearScrollRequest) {
 	return func(r *ClearScrollRequest) {
-		r.Body = v
+		r.ScrollID = v
 	}
 }
 
@@ -167,3 +202,27 @@ func (f ClearScroll) WithFilterPath(v ...string) func(*ClearScrollRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClearScroll) WithHeader(h map[string]string) func(*ClearScrollRequest) {
+	return func(r *ClearScrollRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClearScroll) WithOpaqueID(s string) func(*ClearScrollRequest) {
+	return func(r *ClearScrollRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.allocation_explain.go b/esapi/api.cluster.allocation_explain.go
old mode 100755
new mode 100644
index 4fdd4d1acd..4d5dfada4e
--- a/esapi/api.cluster.allocation_explain.go
+++ b/esapi/api.cluster.allocation_explain.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,11 +41,11 @@ func newClusterAllocationExplainFunc(t Transport) ClusterAllocationExplain {
 
 // ClusterAllocationExplain provides explanations for shard allocations in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-allocation-explain.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-allocation-explain.html.
 //
 type ClusterAllocationExplain func(o ...func(*ClusterAllocationExplainRequest)) (*Response, error)
 
-// ClusterAllocationExplainRequest configures the Cluster  Allocation Explain API request.
+// ClusterAllocationExplainRequest configures the Cluster Allocation Explain API request.
 //
 type ClusterAllocationExplainRequest struct {
 	Body io.Reader
@@ -40,6 +58,8 @@ type ClusterAllocationExplainRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -52,7 +72,7 @@ func (r ClusterAllocationExplainRequest) Do(ctx context.Context, transport Trans
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(len("/_cluster/allocation/explain"))
 	path.WriteString("/_cluster/allocation/explain")
@@ -83,7 +103,10 @@ func (r ClusterAllocationExplainRequest) Do(ctx context.Context, transport Trans
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -97,6 +120,18 @@ func (r ClusterAllocationExplainRequest) Do(ctx context.Context, transport Trans
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -123,7 +158,7 @@ func (f ClusterAllocationExplain) WithContext(v context.Context) func(*ClusterAl
 	}
 }
 
-// WithBody - The index, shard, and primary flag to explain. Empty means 'explain the first unassigned shard'.
+// WithBody - The index, shard, and primary flag to explain. Empty means 'explain a randomly-chosen unassigned shard'.
 //
 func (f ClusterAllocationExplain) WithBody(v io.Reader) func(*ClusterAllocationExplainRequest) {
 	return func(r *ClusterAllocationExplainRequest) {
@@ -178,3 +213,27 @@ func (f ClusterAllocationExplain) WithFilterPath(v ...string) func(*ClusterAlloc
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterAllocationExplain) WithHeader(h map[string]string) func(*ClusterAllocationExplainRequest) {
+	return func(r *ClusterAllocationExplainRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterAllocationExplain) WithOpaqueID(s string) func(*ClusterAllocationExplainRequest) {
+	return func(r *ClusterAllocationExplainRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.delete_component_template.go b/esapi/api.cluster.delete_component_template.go
new file mode 100644
index 0000000000..087b643316
--- /dev/null
+++ b/esapi/api.cluster.delete_component_template.go
@@ -0,0 +1,229 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newClusterDeleteComponentTemplateFunc(t Transport) ClusterDeleteComponentTemplate {
+	return func(name string, o ...func(*ClusterDeleteComponentTemplateRequest)) (*Response, error) {
+		var r = ClusterDeleteComponentTemplateRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterDeleteComponentTemplate deletes a component template
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-template.html.
+//
+type ClusterDeleteComponentTemplate func(name string, o ...func(*ClusterDeleteComponentTemplateRequest)) (*Response, error)
+
+// ClusterDeleteComponentTemplateRequest configures the Cluster Delete Component Template API request.
+//
+type ClusterDeleteComponentTemplateRequest struct {
+	Name string
+
+	MasterTimeout time.Duration
+	Timeout       time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterDeleteComponentTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_component_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_component_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterDeleteComponentTemplate) WithContext(v context.Context) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f ClusterDeleteComponentTemplate) WithMasterTimeout(v time.Duration) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f ClusterDeleteComponentTemplate) WithTimeout(v time.Duration) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterDeleteComponentTemplate) WithPretty() func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterDeleteComponentTemplate) WithHuman() func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterDeleteComponentTemplate) WithErrorTrace() func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterDeleteComponentTemplate) WithFilterPath(v ...string) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterDeleteComponentTemplate) WithHeader(h map[string]string) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterDeleteComponentTemplate) WithOpaqueID(s string) func(*ClusterDeleteComponentTemplateRequest) {
+	return func(r *ClusterDeleteComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.delete_voting_config_exclusions.go b/esapi/api.cluster.delete_voting_config_exclusions.go
new file mode 100644
index 0000000000..fcdc86b331
--- /dev/null
+++ b/esapi/api.cluster.delete_voting_config_exclusions.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newClusterDeleteVotingConfigExclusionsFunc(t Transport) ClusterDeleteVotingConfigExclusions {
+	return func(o ...func(*ClusterDeleteVotingConfigExclusionsRequest)) (*Response, error) {
+		var r = ClusterDeleteVotingConfigExclusionsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterDeleteVotingConfigExclusions clears cluster voting config exclusions.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/voting-config-exclusions.html.
+//
+type ClusterDeleteVotingConfigExclusions func(o ...func(*ClusterDeleteVotingConfigExclusionsRequest)) (*Response, error)
+
+// ClusterDeleteVotingConfigExclusionsRequest configures the Cluster Delete Voting Config Exclusions API request.
+//
+type ClusterDeleteVotingConfigExclusionsRequest struct {
+	WaitForRemoval *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterDeleteVotingConfigExclusionsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(len("/_cluster/voting_config_exclusions"))
+	path.WriteString("/_cluster/voting_config_exclusions")
+
+	params = make(map[string]string)
+
+	if r.WaitForRemoval != nil {
+		params["wait_for_removal"] = strconv.FormatBool(*r.WaitForRemoval)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithContext(v context.Context) func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithWaitForRemoval - specifies whether to wait for all excluded nodes to be removed from the cluster before clearing the voting configuration exclusions list..
+//
+func (f ClusterDeleteVotingConfigExclusions) WithWaitForRemoval(v bool) func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.WaitForRemoval = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithPretty() func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithHuman() func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithErrorTrace() func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithFilterPath(v ...string) func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithHeader(h map[string]string) func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterDeleteVotingConfigExclusions) WithOpaqueID(s string) func(*ClusterDeleteVotingConfigExclusionsRequest) {
+	return func(r *ClusterDeleteVotingConfigExclusionsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.exists_component_template.go b/esapi/api.cluster.exists_component_template.go
new file mode 100644
index 0000000000..65ade798ca
--- /dev/null
+++ b/esapi/api.cluster.exists_component_template.go
@@ -0,0 +1,230 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newClusterExistsComponentTemplateFunc(t Transport) ClusterExistsComponentTemplate {
+	return func(name string, o ...func(*ClusterExistsComponentTemplateRequest)) (*Response, error) {
+		var r = ClusterExistsComponentTemplateRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterExistsComponentTemplate returns information about whether a particular component template exist
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-template.html.
+//
+type ClusterExistsComponentTemplate func(name string, o ...func(*ClusterExistsComponentTemplateRequest)) (*Response, error)
+
+// ClusterExistsComponentTemplateRequest configures the Cluster Exists Component Template API request.
+//
+type ClusterExistsComponentTemplateRequest struct {
+	Name string
+
+	Local         *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterExistsComponentTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "HEAD"
+
+	path.Grow(1 + len("_component_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_component_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Local != nil {
+		params["local"] = strconv.FormatBool(*r.Local)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterExistsComponentTemplate) WithContext(v context.Context) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithLocal - return local information, do not retrieve the state from master node (default: false).
+//
+func (f ClusterExistsComponentTemplate) WithLocal(v bool) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.Local = &v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f ClusterExistsComponentTemplate) WithMasterTimeout(v time.Duration) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterExistsComponentTemplate) WithPretty() func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterExistsComponentTemplate) WithHuman() func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterExistsComponentTemplate) WithErrorTrace() func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterExistsComponentTemplate) WithFilterPath(v ...string) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterExistsComponentTemplate) WithHeader(h map[string]string) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterExistsComponentTemplate) WithOpaqueID(s string) func(*ClusterExistsComponentTemplateRequest) {
+	return func(r *ClusterExistsComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.get_component_template.go b/esapi/api.cluster.get_component_template.go
new file mode 100644
index 0000000000..b396d9fdee
--- /dev/null
+++ b/esapi/api.cluster.get_component_template.go
@@ -0,0 +1,240 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newClusterGetComponentTemplateFunc(t Transport) ClusterGetComponentTemplate {
+	return func(o ...func(*ClusterGetComponentTemplateRequest)) (*Response, error) {
+		var r = ClusterGetComponentTemplateRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterGetComponentTemplate returns one or more component templates
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-template.html.
+//
+type ClusterGetComponentTemplate func(o ...func(*ClusterGetComponentTemplateRequest)) (*Response, error)
+
+// ClusterGetComponentTemplateRequest configures the Cluster Get Component Template API request.
+//
+type ClusterGetComponentTemplateRequest struct {
+	Name []string
+
+	Local         *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterGetComponentTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_component_template") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_component_template")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Local != nil {
+		params["local"] = strconv.FormatBool(*r.Local)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterGetComponentTemplate) WithContext(v context.Context) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - the comma separated names of the component templates.
+//
+func (f ClusterGetComponentTemplate) WithName(v ...string) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.Name = v
+	}
+}
+
+// WithLocal - return local information, do not retrieve the state from master node (default: false).
+//
+func (f ClusterGetComponentTemplate) WithLocal(v bool) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.Local = &v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f ClusterGetComponentTemplate) WithMasterTimeout(v time.Duration) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterGetComponentTemplate) WithPretty() func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterGetComponentTemplate) WithHuman() func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterGetComponentTemplate) WithErrorTrace() func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterGetComponentTemplate) WithFilterPath(v ...string) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterGetComponentTemplate) WithHeader(h map[string]string) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterGetComponentTemplate) WithOpaqueID(s string) func(*ClusterGetComponentTemplateRequest) {
+	return func(r *ClusterGetComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.get_settings.go b/esapi/api.cluster.get_settings.go
old mode 100755
new mode 100644
index cfdcb5c397..c469bfb8ba
--- a/esapi/api.cluster.get_settings.go
+++ b/esapi/api.cluster.get_settings.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,11 +41,11 @@ func newClusterGetSettingsFunc(t Transport) ClusterGetSettings {
 
 // ClusterGetSettings returns cluster settings.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-update-settings.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-get-settings.html.
 //
 type ClusterGetSettings func(o ...func(*ClusterGetSettingsRequest)) (*Response, error)
 
-// ClusterGetSettingsRequest configures the Cluster  Get Settings API request.
+// ClusterGetSettingsRequest configures the Cluster Get Settings API request.
 //
 type ClusterGetSettingsRequest struct {
 	FlatSettings    *bool
@@ -40,6 +58,8 @@ type ClusterGetSettingsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -91,7 +111,10 @@ func (r ClusterGetSettingsRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -101,6 +124,18 @@ func (r ClusterGetSettingsRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -190,3 +225,27 @@ func (f ClusterGetSettings) WithFilterPath(v ...string) func(*ClusterGetSettings
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterGetSettings) WithHeader(h map[string]string) func(*ClusterGetSettingsRequest) {
+	return func(r *ClusterGetSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterGetSettings) WithOpaqueID(s string) func(*ClusterGetSettingsRequest) {
+	return func(r *ClusterGetSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.health.go b/esapi/api.cluster.health.go
old mode 100755
new mode 100644
index ce940ec753..18412cac2c
--- a/esapi/api.cluster.health.go
+++ b/esapi/api.cluster.health.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newClusterHealthFunc(t Transport) ClusterHealth {
 
 // ClusterHealth returns basic information about the health of the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-health.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-health.html.
 //
 type ClusterHealth func(o ...func(*ClusterHealthRequest)) (*Response, error)
 
@@ -32,6 +50,7 @@ type ClusterHealth func(o ...func(*ClusterHealthRequest)) (*Response, error)
 type ClusterHealthRequest struct {
 	Index []string
 
+	ExpandWildcards             string
 	Level                       string
 	Local                       *bool
 	MasterTimeout               time.Duration
@@ -48,6 +67,8 @@ type ClusterHealthRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -74,6 +95,10 @@ func (r ClusterHealthRequest) Do(ctx context.Context, transport Transport) (*Res
 
 	params = make(map[string]string)
 
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
 	if r.Level != "" {
 		params["level"] = r.Level
 	}
@@ -130,7 +155,10 @@ func (r ClusterHealthRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -140,6 +168,18 @@ func (r ClusterHealthRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -174,6 +214,14 @@ func (f ClusterHealth) WithIndex(v ...string) func(*ClusterHealthRequest) {
 	}
 }
 
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f ClusterHealth) WithExpandWildcards(v string) func(*ClusterHealthRequest) {
+	return func(r *ClusterHealthRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
 // WithLevel - specify the level of detail for returned information.
 //
 func (f ClusterHealth) WithLevel(v string) func(*ClusterHealthRequest) {
@@ -285,3 +333,27 @@ func (f ClusterHealth) WithFilterPath(v ...string) func(*ClusterHealthRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterHealth) WithHeader(h map[string]string) func(*ClusterHealthRequest) {
+	return func(r *ClusterHealthRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterHealth) WithOpaqueID(s string) func(*ClusterHealthRequest) {
+	return func(r *ClusterHealthRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.pending_tasks.go b/esapi/api.cluster.pending_tasks.go
old mode 100755
new mode 100644
index c1c56fe693..c024899682
--- a/esapi/api.cluster.pending_tasks.go
+++ b/esapi/api.cluster.pending_tasks.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,11 +42,11 @@ func newClusterPendingTasksFunc(t Transport) ClusterPendingTasks {
 // ClusterPendingTasks returns a list of any cluster-level changes (e.g. create index, update mapping,
 // allocate or fail shard) which have not yet been executed.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-pending.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-pending.html.
 //
 type ClusterPendingTasks func(o ...func(*ClusterPendingTasksRequest)) (*Response, error)
 
-// ClusterPendingTasksRequest configures the Cluster  Pending Tasks API request.
+// ClusterPendingTasksRequest configures the Cluster Pending Tasks API request.
 //
 type ClusterPendingTasksRequest struct {
 	Local         *bool
@@ -39,6 +57,8 @@ type ClusterPendingTasksRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -82,7 +102,10 @@ func (r ClusterPendingTasksRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -92,6 +115,18 @@ func (r ClusterPendingTasksRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -165,3 +200,27 @@ func (f ClusterPendingTasks) WithFilterPath(v ...string) func(*ClusterPendingTas
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterPendingTasks) WithHeader(h map[string]string) func(*ClusterPendingTasksRequest) {
+	return func(r *ClusterPendingTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterPendingTasks) WithOpaqueID(s string) func(*ClusterPendingTasksRequest) {
+	return func(r *ClusterPendingTasksRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.post_voting_config_exclusions.go b/esapi/api.cluster.post_voting_config_exclusions.go
new file mode 100644
index 0000000000..1e2f55d5ce
--- /dev/null
+++ b/esapi/api.cluster.post_voting_config_exclusions.go
@@ -0,0 +1,237 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newClusterPostVotingConfigExclusionsFunc(t Transport) ClusterPostVotingConfigExclusions {
+	return func(o ...func(*ClusterPostVotingConfigExclusionsRequest)) (*Response, error) {
+		var r = ClusterPostVotingConfigExclusionsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterPostVotingConfigExclusions updates the cluster voting config exclusions by node ids or node names.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/voting-config-exclusions.html.
+//
+type ClusterPostVotingConfigExclusions func(o ...func(*ClusterPostVotingConfigExclusionsRequest)) (*Response, error)
+
+// ClusterPostVotingConfigExclusionsRequest configures the Cluster Post Voting Config Exclusions API request.
+//
+type ClusterPostVotingConfigExclusionsRequest struct {
+	NodeIds   string
+	NodeNames string
+	Timeout   time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterPostVotingConfigExclusionsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_cluster/voting_config_exclusions"))
+	path.WriteString("/_cluster/voting_config_exclusions")
+
+	params = make(map[string]string)
+
+	if r.NodeIds != "" {
+		params["node_ids"] = r.NodeIds
+	}
+
+	if r.NodeNames != "" {
+		params["node_names"] = r.NodeNames
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterPostVotingConfigExclusions) WithContext(v context.Context) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithNodeIds - a list of the persistent ids of the nodes to exclude from the voting configuration. if specified, you may not also specify ?node_names..
+//
+func (f ClusterPostVotingConfigExclusions) WithNodeIds(v string) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.NodeIds = v
+	}
+}
+
+// WithNodeNames - a list of the names of the nodes to exclude from the voting configuration. if specified, you may not also specify ?node_ids..
+//
+func (f ClusterPostVotingConfigExclusions) WithNodeNames(v string) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.NodeNames = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f ClusterPostVotingConfigExclusions) WithTimeout(v time.Duration) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterPostVotingConfigExclusions) WithPretty() func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterPostVotingConfigExclusions) WithHuman() func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterPostVotingConfigExclusions) WithErrorTrace() func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterPostVotingConfigExclusions) WithFilterPath(v ...string) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterPostVotingConfigExclusions) WithHeader(h map[string]string) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterPostVotingConfigExclusions) WithOpaqueID(s string) func(*ClusterPostVotingConfigExclusionsRequest) {
+	return func(r *ClusterPostVotingConfigExclusionsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.put_component_template.go b/esapi/api.cluster.put_component_template.go
new file mode 100644
index 0000000000..80282ddc9f
--- /dev/null
+++ b/esapi/api.cluster.put_component_template.go
@@ -0,0 +1,250 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newClusterPutComponentTemplateFunc(t Transport) ClusterPutComponentTemplate {
+	return func(name string, body io.Reader, o ...func(*ClusterPutComponentTemplateRequest)) (*Response, error) {
+		var r = ClusterPutComponentTemplateRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClusterPutComponentTemplate creates or updates a component template
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-template.html.
+//
+type ClusterPutComponentTemplate func(name string, body io.Reader, o ...func(*ClusterPutComponentTemplateRequest)) (*Response, error)
+
+// ClusterPutComponentTemplateRequest configures the Cluster Put Component Template API request.
+//
+type ClusterPutComponentTemplateRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Create        *bool
+	MasterTimeout time.Duration
+	Timeout       time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClusterPutComponentTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_component_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_component_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Create != nil {
+		params["create"] = strconv.FormatBool(*r.Create)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClusterPutComponentTemplate) WithContext(v context.Context) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithCreate - whether the index template should only be added if new or can also replace an existing one.
+//
+func (f ClusterPutComponentTemplate) WithCreate(v bool) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.Create = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f ClusterPutComponentTemplate) WithMasterTimeout(v time.Duration) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f ClusterPutComponentTemplate) WithTimeout(v time.Duration) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClusterPutComponentTemplate) WithPretty() func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClusterPutComponentTemplate) WithHuman() func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClusterPutComponentTemplate) WithErrorTrace() func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClusterPutComponentTemplate) WithFilterPath(v ...string) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterPutComponentTemplate) WithHeader(h map[string]string) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterPutComponentTemplate) WithOpaqueID(s string) func(*ClusterPutComponentTemplateRequest) {
+	return func(r *ClusterPutComponentTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.put_settings.go b/esapi/api.cluster.put_settings.go
old mode 100755
new mode 100644
index 4fbc95c045..f2143708a2
--- a/esapi/api.cluster.put_settings.go
+++ b/esapi/api.cluster.put_settings.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,11 +42,11 @@ func newClusterPutSettingsFunc(t Transport) ClusterPutSettings {
 
 // ClusterPutSettings updates the cluster settings.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-update-settings.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-update-settings.html.
 //
 type ClusterPutSettings func(body io.Reader, o ...func(*ClusterPutSettingsRequest)) (*Response, error)
 
-// ClusterPutSettingsRequest configures the Cluster  Put Settings API request.
+// ClusterPutSettingsRequest configures the Cluster Put Settings API request.
 //
 type ClusterPutSettingsRequest struct {
 	Body io.Reader
@@ -42,6 +60,8 @@ type ClusterPutSettingsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -89,7 +109,10 @@ func (r ClusterPutSettingsRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -103,6 +126,18 @@ func (r ClusterPutSettingsRequest) Do(ctx context.Context, transport Transport)
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -184,3 +219,27 @@ func (f ClusterPutSettings) WithFilterPath(v ...string) func(*ClusterPutSettings
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterPutSettings) WithHeader(h map[string]string) func(*ClusterPutSettingsRequest) {
+	return func(r *ClusterPutSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterPutSettings) WithOpaqueID(s string) func(*ClusterPutSettingsRequest) {
+	return func(r *ClusterPutSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.remote_info.go b/esapi/api.cluster.remote_info.go
old mode 100755
new mode 100644
index 4e6b47e9b0..7dd70c7232
--- a/esapi/api.cluster.remote_info.go
+++ b/esapi/api.cluster.remote_info.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 )
 
@@ -21,11 +39,11 @@ func newClusterRemoteInfoFunc(t Transport) ClusterRemoteInfo {
 
 // ClusterRemoteInfo returns the information about configured remote clusters.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-remote-info.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-remote-info.html.
 //
 type ClusterRemoteInfo func(o ...func(*ClusterRemoteInfoRequest)) (*Response, error)
 
-// ClusterRemoteInfoRequest configures the Cluster  Remote Info API request.
+// ClusterRemoteInfoRequest configures the Cluster Remote Info API request.
 //
 type ClusterRemoteInfoRequest struct {
 	Pretty     bool
@@ -33,6 +51,8 @@ type ClusterRemoteInfoRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -68,7 +88,10 @@ func (r ClusterRemoteInfoRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -78,6 +101,18 @@ func (r ClusterRemoteInfoRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -135,3 +170,27 @@ func (f ClusterRemoteInfo) WithFilterPath(v ...string) func(*ClusterRemoteInfoRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterRemoteInfo) WithHeader(h map[string]string) func(*ClusterRemoteInfoRequest) {
+	return func(r *ClusterRemoteInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterRemoteInfo) WithOpaqueID(s string) func(*ClusterRemoteInfoRequest) {
+	return func(r *ClusterRemoteInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.reroute.go b/esapi/api.cluster.reroute.go
old mode 100755
new mode 100644
index 702dcf2d89..02364af1f6
--- a/esapi/api.cluster.reroute.go
+++ b/esapi/api.cluster.reroute.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newClusterRerouteFunc(t Transport) ClusterReroute {
 
 // ClusterReroute allows to manually change the allocation of individual shards in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-reroute.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-reroute.html.
 //
 type ClusterReroute func(o ...func(*ClusterRerouteRequest)) (*Response, error)
 
@@ -45,6 +63,8 @@ type ClusterRerouteRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -104,7 +124,10 @@ func (r ClusterRerouteRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -118,6 +141,18 @@ func (r ClusterRerouteRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -231,3 +266,27 @@ func (f ClusterReroute) WithFilterPath(v ...string) func(*ClusterRerouteRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterReroute) WithHeader(h map[string]string) func(*ClusterRerouteRequest) {
+	return func(r *ClusterRerouteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterReroute) WithOpaqueID(s string) func(*ClusterRerouteRequest) {
+	return func(r *ClusterRerouteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.state.go b/esapi/api.cluster.state.go
old mode 100755
new mode 100644
index f0e2fdfe0e..4041f2ef1b
--- a/esapi/api.cluster.state.go
+++ b/esapi/api.cluster.state.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newClusterStateFunc(t Transport) ClusterState {
 
 // ClusterState returns a comprehensive information about the state of the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-state.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-state.html.
 //
 type ClusterState func(o ...func(*ClusterStateRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type ClusterState func(o ...func(*ClusterStateRequest)) (*Response, error)
 type ClusterStateRequest struct {
 	Index []string
 
-	Metric                 []string
+	Metric []string
+
 	AllowNoIndices         *bool
 	ExpandWildcards        string
 	FlatSettings           *bool
@@ -47,6 +66,8 @@ type ClusterStateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -125,7 +146,10 @@ func (r ClusterStateRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -135,6 +159,18 @@ func (r ClusterStateRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -272,3 +308,27 @@ func (f ClusterState) WithFilterPath(v ...string) func(*ClusterStateRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterState) WithHeader(h map[string]string) func(*ClusterStateRequest) {
+	return func(r *ClusterStateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterState) WithOpaqueID(s string) func(*ClusterStateRequest) {
+	return func(r *ClusterStateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.cluster.stats.go b/esapi/api.cluster.stats.go
old mode 100755
new mode 100644
index 3e3407575e..b738940264
--- a/esapi/api.cluster.stats.go
+++ b/esapi/api.cluster.stats.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newClusterStatsFunc(t Transport) ClusterStats {
 
 // ClusterStats returns high-level overview of cluster statistics.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-stats.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-stats.html.
 //
 type ClusterStats func(o ...func(*ClusterStatsRequest)) (*Response, error)
 
 // ClusterStatsRequest configures the Cluster Stats API request.
 //
 type ClusterStatsRequest struct {
-	NodeID       []string
+	NodeID []string
+
 	FlatSettings *bool
 	Timeout      time.Duration
 
@@ -39,6 +58,8 @@ type ClusterStatsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -91,7 +112,10 @@ func (r ClusterStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -101,6 +125,18 @@ func (r ClusterStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -182,3 +218,27 @@ func (f ClusterStats) WithFilterPath(v ...string) func(*ClusterStatsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClusterStats) WithHeader(h map[string]string) func(*ClusterStatsRequest) {
+	return func(r *ClusterStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClusterStats) WithOpaqueID(s string) func(*ClusterStatsRequest) {
+	return func(r *ClusterStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.count.go b/esapi/api.count.go
old mode 100755
new mode 100644
index 14a0832ed0..8323f9b131
--- a/esapi/api.count.go
+++ b/esapi/api.count.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newCountFunc(t Transport) Count {
 
 // Count returns number of documents matching a query.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-count.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-count.html.
 //
 type Count func(o ...func(*CountRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type Count func(o ...func(*CountRequest)) (*Response, error)
 type CountRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices    *bool
 	Analyzer          string
@@ -54,6 +73,8 @@ type CountRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -154,7 +175,10 @@ func (r CountRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -168,6 +192,18 @@ func (r CountRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -194,6 +230,14 @@ func (f Count) WithContext(v context.Context) func(*CountRequest) {
 	}
 }
 
+// WithBody - A query to restrict the results specified with the Query DSL (optional).
+//
+func (f Count) WithBody(v io.Reader) func(*CountRequest) {
+	return func(r *CountRequest) {
+		r.Body = v
+	}
+}
+
 // WithIndex - a list of indices to restrict the results.
 //
 func (f Count) WithIndex(v ...string) func(*CountRequest) {
@@ -210,14 +254,6 @@ func (f Count) WithDocumentType(v ...string) func(*CountRequest) {
 	}
 }
 
-// WithBody - A query to restrict the results specified with the Query DSL (optional).
-//
-func (f Count) WithBody(v io.Reader) func(*CountRequest) {
-	return func(r *CountRequest) {
-		r.Body = v
-	}
-}
-
 // WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
 //
 func (f Count) WithAllowNoIndices(v bool) func(*CountRequest) {
@@ -361,3 +397,27 @@ func (f Count) WithFilterPath(v ...string) func(*CountRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Count) WithHeader(h map[string]string) func(*CountRequest) {
+	return func(r *CountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Count) WithOpaqueID(s string) func(*CountRequest) {
+	return func(r *CountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.create.go b/esapi/api.create.go
old mode 100755
new mode 100644
index d605227da4..517e8c8cfe
--- a/esapi/api.create.go
+++ b/esapi/api.create.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -26,7 +44,7 @@ func newCreateFunc(t Transport) Create {
 //
 // Returns a 409 response when a document with a same ID already exists in the index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-index_.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-index_.html.
 //
 type Create func(index string, id string, body io.Reader, o ...func(*CreateRequest)) (*Response, error)
 
@@ -36,9 +54,9 @@ type CreateRequest struct {
 	Index        string
 	DocumentType string
 	DocumentID   string
-	Body         io.Reader
 
-	Parent              string
+	Body io.Reader
+
 	Pipeline            string
 	Refresh             string
 	Routing             string
@@ -52,6 +70,8 @@ type CreateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -73,8 +93,10 @@ func (r CreateRequest) Do(ctx context.Context, transport Transport) (*Response,
 	path.Grow(1 + len(r.Index) + 1 + len(r.DocumentType) + 1 + len(r.DocumentID) + 1 + len("_create"))
 	path.WriteString("/")
 	path.WriteString(r.Index)
-	path.WriteString("/")
-	path.WriteString(r.DocumentType)
+	if r.DocumentType != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentType)
+	}
 	path.WriteString("/")
 	path.WriteString(r.DocumentID)
 	path.WriteString("/")
@@ -82,10 +104,6 @@ func (r CreateRequest) Do(ctx context.Context, transport Transport) (*Response,
 
 	params = make(map[string]string)
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Pipeline != "" {
 		params["pipeline"] = r.Pipeline
 	}
@@ -130,7 +148,10 @@ func (r CreateRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -144,6 +165,18 @@ func (r CreateRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -178,14 +211,6 @@ func (f Create) WithDocumentType(v string) func(*CreateRequest) {
 	}
 }
 
-// WithParent - ID of the parent document.
-//
-func (f Create) WithParent(v string) func(*CreateRequest) {
-	return func(r *CreateRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPipeline - the pipeline ID to preprocess incoming documents with.
 //
 func (f Create) WithPipeline(v string) func(*CreateRequest) {
@@ -273,3 +298,27 @@ func (f Create) WithFilterPath(v ...string) func(*CreateRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Create) WithHeader(h map[string]string) func(*CreateRequest) {
+	return func(r *CreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Create) WithOpaqueID(s string) func(*CreateRequest) {
+	return func(r *CreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.dangling_indices.delete_dangling_index.go b/esapi/api.dangling_indices.delete_dangling_index.go
new file mode 100644
index 0000000000..7c302034a7
--- /dev/null
+++ b/esapi/api.dangling_indices.delete_dangling_index.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newDanglingIndicesDeleteDanglingIndexFunc(t Transport) DanglingIndicesDeleteDanglingIndex {
+	return func(index_uuid string, o ...func(*DanglingIndicesDeleteDanglingIndexRequest)) (*Response, error) {
+		var r = DanglingIndicesDeleteDanglingIndexRequest{IndexUUID: index_uuid}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DanglingIndicesDeleteDanglingIndex deletes the specified dangling index
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-gateway-dangling-indices.html.
+//
+type DanglingIndicesDeleteDanglingIndex func(index_uuid string, o ...func(*DanglingIndicesDeleteDanglingIndexRequest)) (*Response, error)
+
+// DanglingIndicesDeleteDanglingIndexRequest configures the Dangling Indices Delete Dangling Index API request.
+//
+type DanglingIndicesDeleteDanglingIndexRequest struct {
+	IndexUUID string
+
+	AcceptDataLoss *bool
+	MasterTimeout  time.Duration
+	Timeout        time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DanglingIndicesDeleteDanglingIndexRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_dangling") + 1 + len(r.IndexUUID))
+	path.WriteString("/")
+	path.WriteString("_dangling")
+	path.WriteString("/")
+	path.WriteString(r.IndexUUID)
+
+	params = make(map[string]string)
+
+	if r.AcceptDataLoss != nil {
+		params["accept_data_loss"] = strconv.FormatBool(*r.AcceptDataLoss)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithContext(v context.Context) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcceptDataLoss - must be set to true in order to delete the dangling index.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithAcceptDataLoss(v bool) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.AcceptDataLoss = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithMasterTimeout(v time.Duration) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithTimeout(v time.Duration) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithPretty() func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithHuman() func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithErrorTrace() func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithFilterPath(v ...string) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithHeader(h map[string]string) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DanglingIndicesDeleteDanglingIndex) WithOpaqueID(s string) func(*DanglingIndicesDeleteDanglingIndexRequest) {
+	return func(r *DanglingIndicesDeleteDanglingIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.dangling_indices.import_dangling_index.go b/esapi/api.dangling_indices.import_dangling_index.go
new file mode 100644
index 0000000000..e2ba094f4c
--- /dev/null
+++ b/esapi/api.dangling_indices.import_dangling_index.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newDanglingIndicesImportDanglingIndexFunc(t Transport) DanglingIndicesImportDanglingIndex {
+	return func(index_uuid string, o ...func(*DanglingIndicesImportDanglingIndexRequest)) (*Response, error) {
+		var r = DanglingIndicesImportDanglingIndexRequest{IndexUUID: index_uuid}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DanglingIndicesImportDanglingIndex imports the specified dangling index
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-gateway-dangling-indices.html.
+//
+type DanglingIndicesImportDanglingIndex func(index_uuid string, o ...func(*DanglingIndicesImportDanglingIndexRequest)) (*Response, error)
+
+// DanglingIndicesImportDanglingIndexRequest configures the Dangling Indices Import Dangling Index API request.
+//
+type DanglingIndicesImportDanglingIndexRequest struct {
+	IndexUUID string
+
+	AcceptDataLoss *bool
+	MasterTimeout  time.Duration
+	Timeout        time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DanglingIndicesImportDanglingIndexRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_dangling") + 1 + len(r.IndexUUID))
+	path.WriteString("/")
+	path.WriteString("_dangling")
+	path.WriteString("/")
+	path.WriteString(r.IndexUUID)
+
+	params = make(map[string]string)
+
+	if r.AcceptDataLoss != nil {
+		params["accept_data_loss"] = strconv.FormatBool(*r.AcceptDataLoss)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DanglingIndicesImportDanglingIndex) WithContext(v context.Context) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcceptDataLoss - must be set to true in order to import the dangling index.
+//
+func (f DanglingIndicesImportDanglingIndex) WithAcceptDataLoss(v bool) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.AcceptDataLoss = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f DanglingIndicesImportDanglingIndex) WithMasterTimeout(v time.Duration) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f DanglingIndicesImportDanglingIndex) WithTimeout(v time.Duration) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DanglingIndicesImportDanglingIndex) WithPretty() func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DanglingIndicesImportDanglingIndex) WithHuman() func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DanglingIndicesImportDanglingIndex) WithErrorTrace() func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DanglingIndicesImportDanglingIndex) WithFilterPath(v ...string) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DanglingIndicesImportDanglingIndex) WithHeader(h map[string]string) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DanglingIndicesImportDanglingIndex) WithOpaqueID(s string) func(*DanglingIndicesImportDanglingIndexRequest) {
+	return func(r *DanglingIndicesImportDanglingIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.dangling_indices.list_dangling_indices.go b/esapi/api.dangling_indices.list_dangling_indices.go
new file mode 100644
index 0000000000..6d0d65e131
--- /dev/null
+++ b/esapi/api.dangling_indices.list_dangling_indices.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newDanglingIndicesListDanglingIndicesFunc(t Transport) DanglingIndicesListDanglingIndices {
+	return func(o ...func(*DanglingIndicesListDanglingIndicesRequest)) (*Response, error) {
+		var r = DanglingIndicesListDanglingIndicesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DanglingIndicesListDanglingIndices returns all dangling indices.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-gateway-dangling-indices.html.
+//
+type DanglingIndicesListDanglingIndices func(o ...func(*DanglingIndicesListDanglingIndicesRequest)) (*Response, error)
+
+// DanglingIndicesListDanglingIndicesRequest configures the Dangling Indices List Dangling Indices API request.
+//
+type DanglingIndicesListDanglingIndicesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DanglingIndicesListDanglingIndicesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_dangling"))
+	path.WriteString("/_dangling")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DanglingIndicesListDanglingIndices) WithContext(v context.Context) func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DanglingIndicesListDanglingIndices) WithPretty() func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DanglingIndicesListDanglingIndices) WithHuman() func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DanglingIndicesListDanglingIndices) WithErrorTrace() func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DanglingIndicesListDanglingIndices) WithFilterPath(v ...string) func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DanglingIndicesListDanglingIndices) WithHeader(h map[string]string) func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DanglingIndicesListDanglingIndices) WithOpaqueID(s string) func(*DanglingIndicesListDanglingIndicesRequest) {
+	return func(r *DanglingIndicesListDanglingIndicesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.delete.go b/esapi/api.delete.go
old mode 100755
new mode 100644
index a1d90d89e2..8f9763b95c
--- a/esapi/api.delete.go
+++ b/esapi/api.delete.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newDeleteFunc(t Transport) Delete {
 
 // Delete removes a document from the index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-delete.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-delete.html.
 //
 type Delete func(index string, id string, o ...func(*DeleteRequest)) (*Response, error)
 
@@ -36,7 +54,6 @@ type DeleteRequest struct {
 
 	IfPrimaryTerm       *int
 	IfSeqNo             *int
-	Parent              string
 	Refresh             string
 	Routing             string
 	Timeout             time.Duration
@@ -49,6 +66,8 @@ type DeleteRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -87,10 +106,6 @@ func (r DeleteRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["if_seq_no"] = strconv.FormatInt(int64(*r.IfSeqNo), 10)
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Refresh != "" {
 		params["refresh"] = r.Refresh
 	}
@@ -131,7 +146,10 @@ func (r DeleteRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -141,6 +159,18 @@ func (r DeleteRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,15 +221,7 @@ func (f Delete) WithIfSeqNo(v int) func(*DeleteRequest) {
 	}
 }
 
-// WithParent - ID of parent document.
-//
-func (f Delete) WithParent(v string) func(*DeleteRequest) {
-	return func(r *DeleteRequest) {
-		r.Parent = v
-	}
-}
-
-// WithRefresh - if `true` then refresh the effected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
+// WithRefresh - if `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
 //
 func (f Delete) WithRefresh(v string) func(*DeleteRequest) {
 	return func(r *DeleteRequest) {
@@ -278,3 +300,27 @@ func (f Delete) WithFilterPath(v ...string) func(*DeleteRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Delete) WithHeader(h map[string]string) func(*DeleteRequest) {
+	return func(r *DeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Delete) WithOpaqueID(s string) func(*DeleteRequest) {
+	return func(r *DeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.delete_by_query.go b/esapi/api.delete_by_query.go
old mode 100755
new mode 100644
index 32e64a0360..5f945ab17f
--- a/esapi/api.delete_by_query.go
+++ b/esapi/api.delete_by_query.go
@@ -1,10 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"fmt"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -33,7 +52,8 @@ type DeleteByQuery func(index []string, body io.Reader, o ...func(*DeleteByQuery
 type DeleteByQueryRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices      *bool
 	Analyzer            string
@@ -45,6 +65,7 @@ type DeleteByQueryRequest struct {
 	From                *int
 	IgnoreUnavailable   *bool
 	Lenient             *bool
+	MaxDocs             *int
 	Preference          string
 	Query               string
 	Refresh             *bool
@@ -56,11 +77,8 @@ type DeleteByQueryRequest struct {
 	SearchTimeout       time.Duration
 	SearchType          string
 	Size                *int
-	Slices              *int
+	Slices              interface{}
 	Sort                []string
-	Source              []string
-	SourceExcludes      []string
-	SourceIncludes      []string
 	Stats               []string
 	TerminateAfter      *int
 	Timeout             time.Duration
@@ -73,6 +91,8 @@ type DeleteByQueryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -139,6 +159,10 @@ func (r DeleteByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["lenient"] = strconv.FormatBool(*r.Lenient)
 	}
 
+	if r.MaxDocs != nil {
+		params["max_docs"] = strconv.FormatInt(int64(*r.MaxDocs), 10)
+	}
+
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -184,25 +208,13 @@ func (r DeleteByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 	}
 
 	if r.Slices != nil {
-		params["slices"] = strconv.FormatInt(int64(*r.Slices), 10)
+		params["slices"] = fmt.Sprintf("%v", r.Slices)
 	}
 
 	if len(r.Sort) > 0 {
 		params["sort"] = strings.Join(r.Sort, ",")
 	}
 
-	if len(r.Source) > 0 {
-		params["_source"] = strings.Join(r.Source, ",")
-	}
-
-	if len(r.SourceExcludes) > 0 {
-		params["_source_excludes"] = strings.Join(r.SourceExcludes, ",")
-	}
-
-	if len(r.SourceIncludes) > 0 {
-		params["_source_includes"] = strings.Join(r.SourceIncludes, ",")
-	}
-
 	if len(r.Stats) > 0 {
 		params["stats"] = strings.Join(r.Stats, ",")
 	}
@@ -243,7 +255,10 @@ func (r DeleteByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -257,6 +272,18 @@ func (r DeleteByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -371,6 +398,14 @@ func (f DeleteByQuery) WithLenient(v bool) func(*DeleteByQueryRequest) {
 	}
 }
 
+// WithMaxDocs - maximum number of documents to process (default: all documents).
+//
+func (f DeleteByQuery) WithMaxDocs(v int) func(*DeleteByQueryRequest) {
+	return func(r *DeleteByQueryRequest) {
+		r.MaxDocs = &v
+	}
+}
+
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f DeleteByQuery) WithPreference(v string) func(*DeleteByQueryRequest) {
@@ -451,7 +486,7 @@ func (f DeleteByQuery) WithSearchType(v string) func(*DeleteByQueryRequest) {
 	}
 }
 
-// WithSize - number of hits to return (default: 10).
+// WithSize - deprecated, please use `max_docs` instead.
 //
 func (f DeleteByQuery) WithSize(v int) func(*DeleteByQueryRequest) {
 	return func(r *DeleteByQueryRequest) {
@@ -459,11 +494,11 @@ func (f DeleteByQuery) WithSize(v int) func(*DeleteByQueryRequest) {
 	}
 }
 
-// WithSlices - the number of slices this task should be divided into. defaults to 1 meaning the task isn't sliced into subtasks..
+// WithSlices - the number of slices this task should be divided into. defaults to 1, meaning the task isn't sliced into subtasks. can be set to `auto`..
 //
-func (f DeleteByQuery) WithSlices(v int) func(*DeleteByQueryRequest) {
+func (f DeleteByQuery) WithSlices(v interface{}) func(*DeleteByQueryRequest) {
 	return func(r *DeleteByQueryRequest) {
-		r.Slices = &v
+		r.Slices = v
 	}
 }
 
@@ -475,30 +510,6 @@ func (f DeleteByQuery) WithSort(v ...string) func(*DeleteByQueryRequest) {
 	}
 }
 
-// WithSource - true or false to return the _source field or not, or a list of fields to return.
-//
-func (f DeleteByQuery) WithSource(v ...string) func(*DeleteByQueryRequest) {
-	return func(r *DeleteByQueryRequest) {
-		r.Source = v
-	}
-}
-
-// WithSourceExcludes - a list of fields to exclude from the returned _source field.
-//
-func (f DeleteByQuery) WithSourceExcludes(v ...string) func(*DeleteByQueryRequest) {
-	return func(r *DeleteByQueryRequest) {
-		r.SourceExcludes = v
-	}
-}
-
-// WithSourceIncludes - a list of fields to extract and return from the _source field.
-//
-func (f DeleteByQuery) WithSourceIncludes(v ...string) func(*DeleteByQueryRequest) {
-	return func(r *DeleteByQueryRequest) {
-		r.SourceIncludes = v
-	}
-}
-
 // WithStats - specific 'tag' of the request for logging and statistical purposes.
 //
 func (f DeleteByQuery) WithStats(v ...string) func(*DeleteByQueryRequest) {
@@ -578,3 +589,27 @@ func (f DeleteByQuery) WithFilterPath(v ...string) func(*DeleteByQueryRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DeleteByQuery) WithHeader(h map[string]string) func(*DeleteByQueryRequest) {
+	return func(r *DeleteByQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DeleteByQuery) WithOpaqueID(s string) func(*DeleteByQueryRequest) {
+	return func(r *DeleteByQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.delete_by_query_rethrottle.go b/esapi/api.delete_by_query_rethrottle.go
old mode 100755
new mode 100644
index 0448290904..63bba850ec
--- a/esapi/api.delete_by_query_rethrottle.go
+++ b/esapi/api.delete_by_query_rethrottle.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -29,7 +47,8 @@ type DeleteByQueryRethrottle func(task_id string, requests_per_second *int, o ..
 // DeleteByQueryRethrottleRequest configures the Delete By Query Rethrottle API request.
 //
 type DeleteByQueryRethrottleRequest struct {
-	TaskID            string
+	TaskID string
+
 	RequestsPerSecond *int
 
 	Pretty     bool
@@ -37,6 +56,8 @@ type DeleteByQueryRethrottleRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -81,7 +102,10 @@ func (r DeleteByQueryRethrottleRequest) Do(ctx context.Context, transport Transp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -91,6 +115,18 @@ func (r DeleteByQueryRethrottleRequest) Do(ctx context.Context, transport Transp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -156,3 +192,27 @@ func (f DeleteByQueryRethrottle) WithFilterPath(v ...string) func(*DeleteByQuery
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DeleteByQueryRethrottle) WithHeader(h map[string]string) func(*DeleteByQueryRethrottleRequest) {
+	return func(r *DeleteByQueryRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DeleteByQueryRethrottle) WithOpaqueID(s string) func(*DeleteByQueryRethrottleRequest) {
+	return func(r *DeleteByQueryRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.delete_script.go b/esapi/api.delete_script.go
old mode 100755
new mode 100644
index 7c96281181..90f8b3020d
--- a/esapi/api.delete_script.go
+++ b/esapi/api.delete_script.go
@@ -1,16 +1,34 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
 
 func newDeleteScriptFunc(t Transport) DeleteScript {
 	return func(id string, o ...func(*DeleteScriptRequest)) (*Response, error) {
-		var r = DeleteScriptRequest{DocumentID: id}
+		var r = DeleteScriptRequest{ScriptID: id}
 		for _, f := range o {
 			f(&r)
 		}
@@ -22,14 +40,14 @@ func newDeleteScriptFunc(t Transport) DeleteScript {
 
 // DeleteScript deletes a script.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
 //
 type DeleteScript func(id string, o ...func(*DeleteScriptRequest)) (*Response, error)
 
 // DeleteScriptRequest configures the Delete Script API request.
 //
 type DeleteScriptRequest struct {
-	DocumentID string
+	ScriptID string
 
 	MasterTimeout time.Duration
 	Timeout       time.Duration
@@ -39,6 +57,8 @@ type DeleteScriptRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -53,11 +73,11 @@ func (r DeleteScriptRequest) Do(ctx context.Context, transport Transport) (*Resp
 
 	method = "DELETE"
 
-	path.Grow(1 + len("_scripts") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_scripts") + 1 + len(r.ScriptID))
 	path.WriteString("/")
 	path.WriteString("_scripts")
 	path.WriteString("/")
-	path.WriteString(r.DocumentID)
+	path.WriteString(r.ScriptID)
 
 	params = make(map[string]string)
 
@@ -85,7 +105,10 @@ func (r DeleteScriptRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -95,6 +118,18 @@ func (r DeleteScriptRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -168,3 +203,27 @@ func (f DeleteScript) WithFilterPath(v ...string) func(*DeleteScriptRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DeleteScript) WithHeader(h map[string]string) func(*DeleteScriptRequest) {
+	return func(r *DeleteScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DeleteScript) WithOpaqueID(s string) func(*DeleteScriptRequest) {
+	return func(r *DeleteScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.exists.go b/esapi/api.exists.go
old mode 100755
new mode 100644
index 24cd9518d7..4dd414f249
--- a/esapi/api.exists.go
+++ b/esapi/api.exists.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newExistsFunc(t Transport) Exists {
 
 // Exists returns information about whether a document exists in an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
 //
 type Exists func(index string, id string, o ...func(*ExistsRequest)) (*Response, error)
 
@@ -33,7 +51,6 @@ type ExistsRequest struct {
 	DocumentType string
 	DocumentID   string
 
-	Parent         string
 	Preference     string
 	Realtime       *bool
 	Refresh        *bool
@@ -50,6 +67,8 @@ type ExistsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -80,10 +99,6 @@ func (r ExistsRequest) Do(ctx context.Context, transport Transport) (*Response,
 
 	params = make(map[string]string)
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -140,7 +155,10 @@ func (r ExistsRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -150,6 +168,18 @@ func (r ExistsRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -184,14 +214,6 @@ func (f Exists) WithDocumentType(v string) func(*ExistsRequest) {
 	}
 }
 
-// WithParent - the ID of the parent document.
-//
-func (f Exists) WithParent(v string) func(*ExistsRequest) {
-	return func(r *ExistsRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f Exists) WithPreference(v string) func(*ExistsRequest) {
@@ -303,3 +325,27 @@ func (f Exists) WithFilterPath(v ...string) func(*ExistsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Exists) WithHeader(h map[string]string) func(*ExistsRequest) {
+	return func(r *ExistsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Exists) WithOpaqueID(s string) func(*ExistsRequest) {
+	return func(r *ExistsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.exists_source.go b/esapi/api.exists_source.go
old mode 100755
new mode 100644
index 3dd7de738d..39a4cef183
--- a/esapi/api.exists_source.go
+++ b/esapi/api.exists_source.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newExistsSourceFunc(t Transport) ExistsSource {
 
 // ExistsSource returns information about whether a document source exists in an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
 //
 type ExistsSource func(index string, id string, o ...func(*ExistsSourceRequest)) (*Response, error)
 
@@ -33,7 +51,6 @@ type ExistsSourceRequest struct {
 	DocumentType string
 	DocumentID   string
 
-	Parent         string
 	Preference     string
 	Realtime       *bool
 	Refresh        *bool
@@ -49,6 +66,8 @@ type ExistsSourceRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -77,10 +96,6 @@ func (r ExistsSourceRequest) Do(ctx context.Context, transport Transport) (*Resp
 
 	params = make(map[string]string)
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -133,7 +148,10 @@ func (r ExistsSourceRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -143,6 +161,18 @@ func (r ExistsSourceRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -177,14 +207,6 @@ func (f ExistsSource) WithDocumentType(v string) func(*ExistsSourceRequest) {
 	}
 }
 
-// WithParent - the ID of the parent document.
-//
-func (f ExistsSource) WithParent(v string) func(*ExistsSourceRequest) {
-	return func(r *ExistsSourceRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f ExistsSource) WithPreference(v string) func(*ExistsSourceRequest) {
@@ -288,3 +310,27 @@ func (f ExistsSource) WithFilterPath(v ...string) func(*ExistsSourceRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ExistsSource) WithHeader(h map[string]string) func(*ExistsSourceRequest) {
+	return func(r *ExistsSourceRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ExistsSource) WithOpaqueID(s string) func(*ExistsSourceRequest) {
+	return func(r *ExistsSourceRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.explain.go b/esapi/api.explain.go
old mode 100755
new mode 100644
index 302b5004a1..d5ba2cdb85
--- a/esapi/api.explain.go
+++ b/esapi/api.explain.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newExplainFunc(t Transport) Explain {
 
 // Explain returns information about why a specific matches (or doesn't match) a query.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-explain.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-explain.html.
 //
 type Explain func(index string, id string, o ...func(*ExplainRequest)) (*Response, error)
 
@@ -33,14 +51,14 @@ type ExplainRequest struct {
 	Index        string
 	DocumentType string
 	DocumentID   string
-	Body         io.Reader
+
+	Body io.Reader
 
 	Analyzer        string
 	AnalyzeWildcard *bool
 	DefaultOperator string
 	Df              string
 	Lenient         *bool
-	Parent          string
 	Preference      string
 	Query           string
 	Routing         string
@@ -54,6 +72,8 @@ type ExplainRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -66,7 +86,7 @@ func (r ExplainRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	if r.DocumentType == "" {
 		r.DocumentType = "_doc"
@@ -106,10 +126,6 @@ func (r ExplainRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["lenient"] = strconv.FormatBool(*r.Lenient)
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -154,7 +170,10 @@ func (r ExplainRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -168,6 +187,18 @@ func (r ExplainRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -194,19 +225,19 @@ func (f Explain) WithContext(v context.Context) func(*ExplainRequest) {
 	}
 }
 
-// WithDocumentType - the type of the document.
+// WithBody - The query definition using the Query DSL.
 //
-func (f Explain) WithDocumentType(v string) func(*ExplainRequest) {
+func (f Explain) WithBody(v io.Reader) func(*ExplainRequest) {
 	return func(r *ExplainRequest) {
-		r.DocumentType = v
+		r.Body = v
 	}
 }
 
-// WithBody - The query definition using the Query DSL.
+// WithDocumentType - the type of the document.
 //
-func (f Explain) WithBody(v io.Reader) func(*ExplainRequest) {
+func (f Explain) WithDocumentType(v string) func(*ExplainRequest) {
 	return func(r *ExplainRequest) {
-		r.Body = v
+		r.DocumentType = v
 	}
 }
 
@@ -250,14 +281,6 @@ func (f Explain) WithLenient(v bool) func(*ExplainRequest) {
 	}
 }
 
-// WithParent - the ID of the parent document.
-//
-func (f Explain) WithParent(v string) func(*ExplainRequest) {
-	return func(r *ExplainRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f Explain) WithPreference(v string) func(*ExplainRequest) {
@@ -345,3 +368,27 @@ func (f Explain) WithFilterPath(v ...string) func(*ExplainRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Explain) WithHeader(h map[string]string) func(*ExplainRequest) {
+	return func(r *ExplainRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Explain) WithOpaqueID(s string) func(*ExplainRequest) {
+	return func(r *ExplainRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.features.get_features.go b/esapi/api.features.get_features.go
new file mode 100644
index 0000000000..2db399ea91
--- /dev/null
+++ b/esapi/api.features.get_features.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newFeaturesGetFeaturesFunc(t Transport) FeaturesGetFeatures {
+	return func(o ...func(*FeaturesGetFeaturesRequest)) (*Response, error) {
+		var r = FeaturesGetFeaturesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// FeaturesGetFeatures gets a list of features which can be included in snapshots using the feature_states field when creating a snapshot
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-features-api.html.
+//
+type FeaturesGetFeatures func(o ...func(*FeaturesGetFeaturesRequest)) (*Response, error)
+
+// FeaturesGetFeaturesRequest configures the Features Get Features API request.
+//
+type FeaturesGetFeaturesRequest struct {
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r FeaturesGetFeaturesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_features"))
+	path.WriteString("/_features")
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f FeaturesGetFeatures) WithContext(v context.Context) func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f FeaturesGetFeatures) WithMasterTimeout(v time.Duration) func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f FeaturesGetFeatures) WithPretty() func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f FeaturesGetFeatures) WithHuman() func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f FeaturesGetFeatures) WithErrorTrace() func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f FeaturesGetFeatures) WithFilterPath(v ...string) func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FeaturesGetFeatures) WithHeader(h map[string]string) func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FeaturesGetFeatures) WithOpaqueID(s string) func(*FeaturesGetFeaturesRequest) {
+	return func(r *FeaturesGetFeaturesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.features.reset_features.go b/esapi/api.features.reset_features.go
new file mode 100644
index 0000000000..a5cb803706
--- /dev/null
+++ b/esapi/api.features.reset_features.go
@@ -0,0 +1,198 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newFeaturesResetFeaturesFunc(t Transport) FeaturesResetFeatures {
+	return func(o ...func(*FeaturesResetFeaturesRequest)) (*Response, error) {
+		var r = FeaturesResetFeaturesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// FeaturesResetFeatures resets the internal state of features, usually by deleting system indices
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+//
+type FeaturesResetFeatures func(o ...func(*FeaturesResetFeaturesRequest)) (*Response, error)
+
+// FeaturesResetFeaturesRequest configures the Features Reset Features API request.
+//
+type FeaturesResetFeaturesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r FeaturesResetFeaturesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_features/_reset"))
+	path.WriteString("/_features/_reset")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f FeaturesResetFeatures) WithContext(v context.Context) func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f FeaturesResetFeatures) WithPretty() func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f FeaturesResetFeatures) WithHuman() func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f FeaturesResetFeatures) WithErrorTrace() func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f FeaturesResetFeatures) WithFilterPath(v ...string) func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FeaturesResetFeatures) WithHeader(h map[string]string) func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FeaturesResetFeatures) WithOpaqueID(s string) func(*FeaturesResetFeaturesRequest) {
+	return func(r *FeaturesResetFeaturesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.field_caps.go b/esapi/api.field_caps.go
old mode 100755
new mode 100644
index 3938ec478b..6fd1b14b16
--- a/esapi/api.field_caps.go
+++ b/esapi/api.field_caps.go
@@ -1,9 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +41,7 @@ func newFieldCapsFunc(t Transport) FieldCaps {
 
 // FieldCaps returns the information about the capabilities of fields among multiple indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-field-caps.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-field-caps.html.
 //
 type FieldCaps func(o ...func(*FieldCapsRequest)) (*Response, error)
 
@@ -31,16 +50,21 @@ type FieldCaps func(o ...func(*FieldCapsRequest)) (*Response, error)
 type FieldCapsRequest struct {
 	Index []string
 
+	Body io.Reader
+
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	Fields            []string
 	IgnoreUnavailable *bool
+	IncludeUnmapped   *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -53,7 +77,7 @@ func (r FieldCapsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_field_caps"))
 	if len(r.Index) > 0 {
@@ -81,6 +105,10 @@ func (r FieldCapsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
 	}
 
+	if r.IncludeUnmapped != nil {
+		params["include_unmapped"] = strconv.FormatBool(*r.IncludeUnmapped)
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -97,7 +125,10 @@ func (r FieldCapsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +138,22 @@ func (r FieldCapsRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -133,6 +180,14 @@ func (f FieldCaps) WithContext(v context.Context) func(*FieldCapsRequest) {
 	}
 }
 
+// WithBody - An index filter specified with the Query DSL.
+//
+func (f FieldCaps) WithBody(v io.Reader) func(*FieldCapsRequest) {
+	return func(r *FieldCapsRequest) {
+		r.Body = v
+	}
+}
+
 // WithIndex - a list of index names; use _all to perform the operation on all indices.
 //
 func (f FieldCaps) WithIndex(v ...string) func(*FieldCapsRequest) {
@@ -173,6 +228,14 @@ func (f FieldCaps) WithIgnoreUnavailable(v bool) func(*FieldCapsRequest) {
 	}
 }
 
+// WithIncludeUnmapped - indicates whether unmapped fields should be included in the response..
+//
+func (f FieldCaps) WithIncludeUnmapped(v bool) func(*FieldCapsRequest) {
+	return func(r *FieldCapsRequest) {
+		r.IncludeUnmapped = &v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f FieldCaps) WithPretty() func(*FieldCapsRequest) {
@@ -204,3 +267,27 @@ func (f FieldCaps) WithFilterPath(v ...string) func(*FieldCapsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FieldCaps) WithHeader(h map[string]string) func(*FieldCapsRequest) {
+	return func(r *FieldCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FieldCaps) WithOpaqueID(s string) func(*FieldCapsRequest) {
+	return func(r *FieldCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.fleet.global_checkpoints.go b/esapi/api.fleet.global_checkpoints.go
new file mode 100644
index 0000000000..e360418bca
--- /dev/null
+++ b/esapi/api.fleet.global_checkpoints.go
@@ -0,0 +1,258 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newFleetGlobalCheckpointsFunc(t Transport) FleetGlobalCheckpoints {
+	return func(index string, o ...func(*FleetGlobalCheckpointsRequest)) (*Response, error) {
+		var r = FleetGlobalCheckpointsRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// FleetGlobalCheckpoints returns the current global checkpoints for an index. This API is design for internal use by the fleet server project.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-global-checkpoints.html.
+//
+type FleetGlobalCheckpoints func(index string, o ...func(*FleetGlobalCheckpointsRequest)) (*Response, error)
+
+// FleetGlobalCheckpointsRequest configures the Fleet Global Checkpoints API request.
+//
+type FleetGlobalCheckpointsRequest struct {
+	Index string
+
+	Checkpoints    []string
+	Timeout        time.Duration
+	WaitForAdvance *bool
+	WaitForIndex   *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r FleetGlobalCheckpointsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_fleet") + 1 + len("global_checkpoints"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_fleet")
+	path.WriteString("/")
+	path.WriteString("global_checkpoints")
+
+	params = make(map[string]string)
+
+	if len(r.Checkpoints) > 0 {
+		params["checkpoints"] = strings.Join(r.Checkpoints, ",")
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForAdvance != nil {
+		params["wait_for_advance"] = strconv.FormatBool(*r.WaitForAdvance)
+	}
+
+	if r.WaitForIndex != nil {
+		params["wait_for_index"] = strconv.FormatBool(*r.WaitForIndex)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f FleetGlobalCheckpoints) WithContext(v context.Context) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithCheckpoints - comma separated list of checkpoints.
+//
+func (f FleetGlobalCheckpoints) WithCheckpoints(v ...string) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.Checkpoints = v
+	}
+}
+
+// WithTimeout - timeout to wait for global checkpoint to advance.
+//
+func (f FleetGlobalCheckpoints) WithTimeout(v time.Duration) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForAdvance - whether to wait for the global checkpoint to advance past the specified current checkpoints.
+//
+func (f FleetGlobalCheckpoints) WithWaitForAdvance(v bool) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.WaitForAdvance = &v
+	}
+}
+
+// WithWaitForIndex - whether to wait for the target index to exist and all primary shards be active.
+//
+func (f FleetGlobalCheckpoints) WithWaitForIndex(v bool) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.WaitForIndex = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f FleetGlobalCheckpoints) WithPretty() func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f FleetGlobalCheckpoints) WithHuman() func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f FleetGlobalCheckpoints) WithErrorTrace() func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f FleetGlobalCheckpoints) WithFilterPath(v ...string) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FleetGlobalCheckpoints) WithHeader(h map[string]string) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FleetGlobalCheckpoints) WithOpaqueID(s string) func(*FleetGlobalCheckpointsRequest) {
+	return func(r *FleetGlobalCheckpointsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.fleet.msearch.go b/esapi/api.fleet.msearch.go
new file mode 100644
index 0000000000..1ce283f1e0
--- /dev/null
+++ b/esapi/api.fleet.msearch.go
@@ -0,0 +1,220 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newFleetMsearchFunc(t Transport) FleetMsearch {
+	return func(body io.Reader, o ...func(*FleetMsearchRequest)) (*Response, error) {
+		var r = FleetMsearchRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// FleetMsearch multi Search API where the search will only be executed after specified checkpoints are available due to a refresh. This API is designed for internal use by the fleet server project.
+//
+// This API is experimental.
+//
+type FleetMsearch func(body io.Reader, o ...func(*FleetMsearchRequest)) (*Response, error)
+
+// FleetMsearchRequest configures the Fleet Msearch API request.
+//
+type FleetMsearchRequest struct {
+	Index string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r FleetMsearchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_fleet") + 1 + len("_fleet_msearch"))
+	if r.Index != "" {
+		path.WriteString("/")
+		path.WriteString(r.Index)
+	}
+	path.WriteString("/")
+	path.WriteString("_fleet")
+	path.WriteString("/")
+	path.WriteString("_fleet_msearch")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f FleetMsearch) WithContext(v context.Context) func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithIndex - the index name to use as the default.
+//
+func (f FleetMsearch) WithIndex(v string) func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.Index = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f FleetMsearch) WithPretty() func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f FleetMsearch) WithHuman() func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f FleetMsearch) WithErrorTrace() func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f FleetMsearch) WithFilterPath(v ...string) func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FleetMsearch) WithHeader(h map[string]string) func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FleetMsearch) WithOpaqueID(s string) func(*FleetMsearchRequest) {
+	return func(r *FleetMsearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.fleet.search.go b/esapi/api.fleet.search.go
new file mode 100644
index 0000000000..d41c92c3d8
--- /dev/null
+++ b/esapi/api.fleet.search.go
@@ -0,0 +1,260 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newFleetSearchFunc(t Transport) FleetSearch {
+	return func(index string, o ...func(*FleetSearchRequest)) (*Response, error) {
+		var r = FleetSearchRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// FleetSearch search API where the search will only be executed after specified checkpoints are available due to a refresh. This API is designed for internal use by the fleet server project.
+//
+// This API is experimental.
+//
+type FleetSearch func(index string, o ...func(*FleetSearchRequest)) (*Response, error)
+
+// FleetSearchRequest configures the Fleet Search API request.
+//
+type FleetSearchRequest struct {
+	Index string
+
+	Body io.Reader
+
+	AllowPartialSearchResults *bool
+	WaitForCheckpoints        []string
+	WaitForCheckpointsTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r FleetSearchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_fleet") + 1 + len("_fleet_search"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_fleet")
+	path.WriteString("/")
+	path.WriteString("_fleet_search")
+
+	params = make(map[string]string)
+
+	if r.AllowPartialSearchResults != nil {
+		params["allow_partial_search_results"] = strconv.FormatBool(*r.AllowPartialSearchResults)
+	}
+
+	if len(r.WaitForCheckpoints) > 0 {
+		params["wait_for_checkpoints"] = strings.Join(r.WaitForCheckpoints, ",")
+	}
+
+	if r.WaitForCheckpointsTimeout != 0 {
+		params["wait_for_checkpoints_timeout"] = formatDuration(r.WaitForCheckpointsTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f FleetSearch) WithContext(v context.Context) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The search definition using the Query DSL.
+//
+func (f FleetSearch) WithBody(v io.Reader) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.Body = v
+	}
+}
+
+// WithAllowPartialSearchResults - indicate if an error should be returned if there is a partial search failure or timeout.
+//
+func (f FleetSearch) WithAllowPartialSearchResults(v bool) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.AllowPartialSearchResults = &v
+	}
+}
+
+// WithWaitForCheckpoints - comma separated list of checkpoints, one per shard.
+//
+func (f FleetSearch) WithWaitForCheckpoints(v ...string) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.WaitForCheckpoints = v
+	}
+}
+
+// WithWaitForCheckpointsTimeout - explicit wait_for_checkpoints timeout.
+//
+func (f FleetSearch) WithWaitForCheckpointsTimeout(v time.Duration) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.WaitForCheckpointsTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f FleetSearch) WithPretty() func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f FleetSearch) WithHuman() func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f FleetSearch) WithErrorTrace() func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f FleetSearch) WithFilterPath(v ...string) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f FleetSearch) WithHeader(h map[string]string) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f FleetSearch) WithOpaqueID(s string) func(*FleetSearchRequest) {
+	return func(r *FleetSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.get.go b/esapi/api.get.go
old mode 100755
new mode 100644
index 2b78eee3b6..a41917cb15
--- a/esapi/api.get.go
+++ b/esapi/api.get.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newGetFunc(t Transport) Get {
 
 // Get returns a document.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
 //
 type Get func(index string, id string, o ...func(*GetRequest)) (*Response, error)
 
@@ -33,15 +51,12 @@ type GetRequest struct {
 	DocumentType string
 	DocumentID   string
 
-	Parent         string
 	Preference     string
 	Realtime       *bool
 	Refresh        *bool
 	Routing        string
 	Source         []string
-	SourceExclude  []string
 	SourceExcludes []string
-	SourceInclude  []string
 	SourceIncludes []string
 	StoredFields   []string
 	Version        *int
@@ -52,6 +67,8 @@ type GetRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -82,10 +99,6 @@ func (r GetRequest) Do(ctx context.Context, transport Transport) (*Response, err
 
 	params = make(map[string]string)
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -106,18 +119,10 @@ func (r GetRequest) Do(ctx context.Context, transport Transport) (*Response, err
 		params["_source"] = strings.Join(r.Source, ",")
 	}
 
-	if len(r.SourceExclude) > 0 {
-		params["_source_exclude"] = strings.Join(r.SourceExclude, ",")
-	}
-
 	if len(r.SourceExcludes) > 0 {
 		params["_source_excludes"] = strings.Join(r.SourceExcludes, ",")
 	}
 
-	if len(r.SourceInclude) > 0 {
-		params["_source_include"] = strings.Join(r.SourceInclude, ",")
-	}
-
 	if len(r.SourceIncludes) > 0 {
 		params["_source_includes"] = strings.Join(r.SourceIncludes, ",")
 	}
@@ -150,7 +155,10 @@ func (r GetRequest) Do(ctx context.Context, transport Transport) (*Response, err
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -160,6 +168,18 @@ func (r GetRequest) Do(ctx context.Context, transport Transport) (*Response, err
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -194,14 +214,6 @@ func (f Get) WithDocumentType(v string) func(*GetRequest) {
 	}
 }
 
-// WithParent - the ID of the parent document.
-//
-func (f Get) WithParent(v string) func(*GetRequest) {
-	return func(r *GetRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f Get) WithPreference(v string) func(*GetRequest) {
@@ -242,14 +254,6 @@ func (f Get) WithSource(v ...string) func(*GetRequest) {
 	}
 }
 
-// WithSourceExclude - a list of fields to exclude from the returned _source field.
-//
-func (f Get) WithSourceExclude(v ...string) func(*GetRequest) {
-	return func(r *GetRequest) {
-		r.SourceExclude = v
-	}
-}
-
 // WithSourceExcludes - a list of fields to exclude from the returned _source field.
 //
 func (f Get) WithSourceExcludes(v ...string) func(*GetRequest) {
@@ -258,14 +262,6 @@ func (f Get) WithSourceExcludes(v ...string) func(*GetRequest) {
 	}
 }
 
-// WithSourceInclude - a list of fields to extract and return from the _source field.
-//
-func (f Get) WithSourceInclude(v ...string) func(*GetRequest) {
-	return func(r *GetRequest) {
-		r.SourceInclude = v
-	}
-}
-
 // WithSourceIncludes - a list of fields to extract and return from the _source field.
 //
 func (f Get) WithSourceIncludes(v ...string) func(*GetRequest) {
@@ -329,3 +325,27 @@ func (f Get) WithFilterPath(v ...string) func(*GetRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Get) WithHeader(h map[string]string) func(*GetRequest) {
+	return func(r *GetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Get) WithOpaqueID(s string) func(*GetRequest) {
+	return func(r *GetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.get_script.go b/esapi/api.get_script.go
old mode 100755
new mode 100644
index be395e4261..b52af63b30
--- a/esapi/api.get_script.go
+++ b/esapi/api.get_script.go
@@ -1,16 +1,34 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
 
 func newGetScriptFunc(t Transport) GetScript {
 	return func(id string, o ...func(*GetScriptRequest)) (*Response, error) {
-		var r = GetScriptRequest{DocumentID: id}
+		var r = GetScriptRequest{ScriptID: id}
 		for _, f := range o {
 			f(&r)
 		}
@@ -22,14 +40,14 @@ func newGetScriptFunc(t Transport) GetScript {
 
 // GetScript returns a script.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
 //
 type GetScript func(id string, o ...func(*GetScriptRequest)) (*Response, error)
 
 // GetScriptRequest configures the Get Script API request.
 //
 type GetScriptRequest struct {
-	DocumentID string
+	ScriptID string
 
 	MasterTimeout time.Duration
 
@@ -38,6 +56,8 @@ type GetScriptRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -52,11 +72,11 @@ func (r GetScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 
 	method = "GET"
 
-	path.Grow(1 + len("_scripts") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_scripts") + 1 + len(r.ScriptID))
 	path.WriteString("/")
 	path.WriteString("_scripts")
 	path.WriteString("/")
-	path.WriteString(r.DocumentID)
+	path.WriteString(r.ScriptID)
 
 	params = make(map[string]string)
 
@@ -80,7 +100,10 @@ func (r GetScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -90,6 +113,18 @@ func (r GetScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -155,3 +190,27 @@ func (f GetScript) WithFilterPath(v ...string) func(*GetScriptRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f GetScript) WithHeader(h map[string]string) func(*GetScriptRequest) {
+	return func(r *GetScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f GetScript) WithOpaqueID(s string) func(*GetScriptRequest) {
+	return func(r *GetScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.get_script_context.go b/esapi/api.get_script_context.go
new file mode 100644
index 0000000000..378d1d1728
--- /dev/null
+++ b/esapi/api.get_script_context.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newGetScriptContextFunc(t Transport) GetScriptContext {
+	return func(o ...func(*GetScriptContextRequest)) (*Response, error) {
+		var r = GetScriptContextRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// GetScriptContext returns all script contexts.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-contexts.html.
+//
+type GetScriptContext func(o ...func(*GetScriptContextRequest)) (*Response, error)
+
+// GetScriptContextRequest configures the Get Script Context API request.
+//
+type GetScriptContextRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r GetScriptContextRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_script_context"))
+	path.WriteString("/_script_context")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f GetScriptContext) WithContext(v context.Context) func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f GetScriptContext) WithPretty() func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f GetScriptContext) WithHuman() func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f GetScriptContext) WithErrorTrace() func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f GetScriptContext) WithFilterPath(v ...string) func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f GetScriptContext) WithHeader(h map[string]string) func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f GetScriptContext) WithOpaqueID(s string) func(*GetScriptContextRequest) {
+	return func(r *GetScriptContextRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.get_script_languages.go b/esapi/api.get_script_languages.go
new file mode 100644
index 0000000000..b78bc1d69b
--- /dev/null
+++ b/esapi/api.get_script_languages.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newGetScriptLanguagesFunc(t Transport) GetScriptLanguages {
+	return func(o ...func(*GetScriptLanguagesRequest)) (*Response, error) {
+		var r = GetScriptLanguagesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// GetScriptLanguages returns available script types, languages and contexts
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
+//
+type GetScriptLanguages func(o ...func(*GetScriptLanguagesRequest)) (*Response, error)
+
+// GetScriptLanguagesRequest configures the Get Script Languages API request.
+//
+type GetScriptLanguagesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r GetScriptLanguagesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_script_language"))
+	path.WriteString("/_script_language")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f GetScriptLanguages) WithContext(v context.Context) func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f GetScriptLanguages) WithPretty() func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f GetScriptLanguages) WithHuman() func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f GetScriptLanguages) WithErrorTrace() func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f GetScriptLanguages) WithFilterPath(v ...string) func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f GetScriptLanguages) WithHeader(h map[string]string) func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f GetScriptLanguages) WithOpaqueID(s string) func(*GetScriptLanguagesRequest) {
+	return func(r *GetScriptLanguagesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.get_source.go b/esapi/api.get_source.go
old mode 100755
new mode 100644
index e1f705d1d6..9a05475876
--- a/esapi/api.get_source.go
+++ b/esapi/api.get_source.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newGetSourceFunc(t Transport) GetSource {
 
 // GetSource returns the source of a document.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-get.html.
 //
 type GetSource func(index string, id string, o ...func(*GetSourceRequest)) (*Response, error)
 
@@ -33,7 +51,6 @@ type GetSourceRequest struct {
 	DocumentType string
 	DocumentID   string
 
-	Parent         string
 	Preference     string
 	Realtime       *bool
 	Refresh        *bool
@@ -49,6 +66,8 @@ type GetSourceRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -81,10 +100,6 @@ func (r GetSourceRequest) Do(ctx context.Context, transport Transport) (*Respons
 
 	params = make(map[string]string)
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -137,7 +152,10 @@ func (r GetSourceRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -147,6 +165,18 @@ func (r GetSourceRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -181,14 +211,6 @@ func (f GetSource) WithDocumentType(v string) func(*GetSourceRequest) {
 	}
 }
 
-// WithParent - the ID of the parent document.
-//
-func (f GetSource) WithParent(v string) func(*GetSourceRequest) {
-	return func(r *GetSourceRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f GetSource) WithPreference(v string) func(*GetSourceRequest) {
@@ -292,3 +314,27 @@ func (f GetSource) WithFilterPath(v ...string) func(*GetSourceRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f GetSource) WithHeader(h map[string]string) func(*GetSourceRequest) {
+	return func(r *GetSourceRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f GetSource) WithOpaqueID(s string) func(*GetSourceRequest) {
+	return func(r *GetSourceRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.index.go b/esapi/api.index.go
old mode 100755
new mode 100644
index ccbc1ab204..9ac85bcb2f
--- a/esapi/api.index.go
+++ b/esapi/api.index.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newIndexFunc(t Transport) Index {
 
 // Index creates or updates a document in an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-index_.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-index_.html.
 //
 type Index func(index string, body io.Reader, o ...func(*IndexRequest)) (*Response, error)
 
@@ -34,14 +52,15 @@ type IndexRequest struct {
 	Index        string
 	DocumentType string
 	DocumentID   string
-	Body         io.Reader
+
+	Body io.Reader
 
 	IfPrimaryTerm       *int
 	IfSeqNo             *int
 	OpType              string
-	Parent              string
 	Pipeline            string
 	Refresh             string
+	RequireAlias        *bool
 	Routing             string
 	Timeout             time.Duration
 	Version             *int
@@ -53,6 +72,8 @@ type IndexRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -78,8 +99,10 @@ func (r IndexRequest) Do(ctx context.Context, transport Transport) (*Response, e
 	path.Grow(1 + len(r.Index) + 1 + len(r.DocumentType) + 1 + len(r.DocumentID))
 	path.WriteString("/")
 	path.WriteString(r.Index)
-	path.WriteString("/")
-	path.WriteString(r.DocumentType)
+	if r.DocumentType != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentType)
+	}
 	if r.DocumentID != "" {
 		path.WriteString("/")
 		path.WriteString(r.DocumentID)
@@ -99,10 +122,6 @@ func (r IndexRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		params["op_type"] = r.OpType
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Pipeline != "" {
 		params["pipeline"] = r.Pipeline
 	}
@@ -111,6 +130,10 @@ func (r IndexRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		params["refresh"] = r.Refresh
 	}
 
+	if r.RequireAlias != nil {
+		params["require_alias"] = strconv.FormatBool(*r.RequireAlias)
+	}
+
 	if r.Routing != "" {
 		params["routing"] = r.Routing
 	}
@@ -147,7 +170,10 @@ func (r IndexRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -161,6 +187,18 @@ func (r IndexRequest) Do(ctx context.Context, transport Transport) (*Response, e
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -219,7 +257,7 @@ func (f Index) WithIfSeqNo(v int) func(*IndexRequest) {
 	}
 }
 
-// WithOpType - explicit operation type.
+// WithOpType - explicit operation type. defaults to `index` for requests with an explicit document ID, and to `create`for requests without an explicit document ID.
 //
 func (f Index) WithOpType(v string) func(*IndexRequest) {
 	return func(r *IndexRequest) {
@@ -227,14 +265,6 @@ func (f Index) WithOpType(v string) func(*IndexRequest) {
 	}
 }
 
-// WithParent - ID of the parent document.
-//
-func (f Index) WithParent(v string) func(*IndexRequest) {
-	return func(r *IndexRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPipeline - the pipeline ID to preprocess incoming documents with.
 //
 func (f Index) WithPipeline(v string) func(*IndexRequest) {
@@ -251,6 +281,14 @@ func (f Index) WithRefresh(v string) func(*IndexRequest) {
 	}
 }
 
+// WithRequireAlias - when true, requires destination to be an alias. default is false.
+//
+func (f Index) WithRequireAlias(v bool) func(*IndexRequest) {
+	return func(r *IndexRequest) {
+		r.RequireAlias = &v
+	}
+}
+
 // WithRouting - specific routing value.
 //
 func (f Index) WithRouting(v string) func(*IndexRequest) {
@@ -322,3 +360,27 @@ func (f Index) WithFilterPath(v ...string) func(*IndexRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Index) WithHeader(h map[string]string) func(*IndexRequest) {
+	return func(r *IndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Index) WithOpaqueID(s string) func(*IndexRequest) {
+	return func(r *IndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.add_block.go b/esapi/api.indices.add_block.go
new file mode 100644
index 0000000000..1de4e00b20
--- /dev/null
+++ b/esapi/api.indices.add_block.go
@@ -0,0 +1,273 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesAddBlockFunc(t Transport) IndicesAddBlock {
+	return func(index []string, block string, o ...func(*IndicesAddBlockRequest)) (*Response, error) {
+		var r = IndicesAddBlockRequest{Index: index, Block: block}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesAddBlock adds a block to an index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules-blocks.html.
+//
+type IndicesAddBlock func(index []string, block string, o ...func(*IndicesAddBlockRequest)) (*Response, error)
+
+// IndicesAddBlockRequest configures the Indices Add Block API request.
+//
+type IndicesAddBlockRequest struct {
+	Index []string
+
+	Block string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreUnavailable *bool
+	MasterTimeout     time.Duration
+	Timeout           time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesAddBlockRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_block") + 1 + len(r.Block))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_block")
+	path.WriteString("/")
+	path.WriteString(r.Block)
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesAddBlock) WithContext(v context.Context) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesAddBlock) WithAllowNoIndices(v bool) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesAddBlock) WithExpandWildcards(v string) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesAddBlock) WithIgnoreUnavailable(v bool) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesAddBlock) WithMasterTimeout(v time.Duration) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f IndicesAddBlock) WithTimeout(v time.Duration) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesAddBlock) WithPretty() func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesAddBlock) WithHuman() func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesAddBlock) WithErrorTrace() func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesAddBlock) WithFilterPath(v ...string) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesAddBlock) WithHeader(h map[string]string) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesAddBlock) WithOpaqueID(s string) func(*IndicesAddBlockRequest) {
+	return func(r *IndicesAddBlockRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.analyze.go b/esapi/api.indices.analyze.go
old mode 100755
new mode 100644
index d8ce8bb43c..837e160f58
--- a/esapi/api.indices.analyze.go
+++ b/esapi/api.indices.analyze.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 )
 
@@ -22,7 +40,7 @@ func newIndicesAnalyzeFunc(t Transport) IndicesAnalyze {
 
 // IndicesAnalyze performs the analysis process on a text and return the tokens breakdown of the text.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-analyze.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-analyze.html.
 //
 type IndicesAnalyze func(o ...func(*IndicesAnalyzeRequest)) (*Response, error)
 
@@ -30,13 +48,16 @@ type IndicesAnalyze func(o ...func(*IndicesAnalyzeRequest)) (*Response, error)
 //
 type IndicesAnalyzeRequest struct {
 	Index string
-	Body  io.Reader
+
+	Body io.Reader
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -49,7 +70,7 @@ func (r IndicesAnalyzeRequest) Do(ctx context.Context, transport Transport) (*Re
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(r.Index) + 1 + len("_analyze"))
 	if r.Index != "" {
@@ -81,7 +102,10 @@ func (r IndicesAnalyzeRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -95,6 +119,18 @@ func (r IndicesAnalyzeRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -121,19 +157,19 @@ func (f IndicesAnalyze) WithContext(v context.Context) func(*IndicesAnalyzeReque
 	}
 }
 
-// WithIndex - the name of the index to scope the operation.
+// WithBody - Define analyzer/tokenizer parameters and the text on which the analysis should be performed.
 //
-func (f IndicesAnalyze) WithIndex(v string) func(*IndicesAnalyzeRequest) {
+func (f IndicesAnalyze) WithBody(v io.Reader) func(*IndicesAnalyzeRequest) {
 	return func(r *IndicesAnalyzeRequest) {
-		r.Index = v
+		r.Body = v
 	}
 }
 
-// WithBody - Define analyzer/tokenizer parameters and the text on which the analysis should be performed.
+// WithIndex - the name of the index to scope the operation.
 //
-func (f IndicesAnalyze) WithBody(v io.Reader) func(*IndicesAnalyzeRequest) {
+func (f IndicesAnalyze) WithIndex(v string) func(*IndicesAnalyzeRequest) {
 	return func(r *IndicesAnalyzeRequest) {
-		r.Body = v
+		r.Index = v
 	}
 }
 
@@ -168,3 +204,27 @@ func (f IndicesAnalyze) WithFilterPath(v ...string) func(*IndicesAnalyzeRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesAnalyze) WithHeader(h map[string]string) func(*IndicesAnalyzeRequest) {
+	return func(r *IndicesAnalyzeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesAnalyze) WithOpaqueID(s string) func(*IndicesAnalyzeRequest) {
+	return func(r *IndicesAnalyzeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.clear_cache.go b/esapi/api.indices.clear_cache.go
old mode 100755
new mode 100644
index 3e02ea34f5..9cc91ce6c6
--- a/esapi/api.indices.clear_cache.go
+++ b/esapi/api.indices.clear_cache.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,11 +40,11 @@ func newIndicesClearCacheFunc(t Transport) IndicesClearCache {
 
 // IndicesClearCache clears all or specific caches for one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-clearcache.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-clearcache.html.
 //
 type IndicesClearCache func(o ...func(*IndicesClearCacheRequest)) (*Response, error)
 
-// IndicesClearCacheRequest configures the Indices  Clear Cache API request.
+// IndicesClearCacheRequest configures the Indices Clear Cache API request.
 //
 type IndicesClearCacheRequest struct {
 	Index []string
@@ -44,6 +62,8 @@ type IndicesClearCacheRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -118,7 +138,10 @@ func (r IndicesClearCacheRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -128,6 +151,18 @@ func (r IndicesClearCacheRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -249,3 +284,27 @@ func (f IndicesClearCache) WithFilterPath(v ...string) func(*IndicesClearCacheRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesClearCache) WithHeader(h map[string]string) func(*IndicesClearCacheRequest) {
+	return func(r *IndicesClearCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesClearCache) WithOpaqueID(s string) func(*IndicesClearCacheRequest) {
+	return func(r *IndicesClearCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.clone.go b/esapi/api.indices.clone.go
new file mode 100644
index 0000000000..946c2bcf4f
--- /dev/null
+++ b/esapi/api.indices.clone.go
@@ -0,0 +1,261 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newIndicesCloneFunc(t Transport) IndicesClone {
+	return func(index string, target string, o ...func(*IndicesCloneRequest)) (*Response, error) {
+		var r = IndicesCloneRequest{Index: index, Target: target}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesClone clones an index
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-clone-index.html.
+//
+type IndicesClone func(index string, target string, o ...func(*IndicesCloneRequest)) (*Response, error)
+
+// IndicesCloneRequest configures the Indices Clone API request.
+//
+type IndicesCloneRequest struct {
+	Index string
+
+	Body io.Reader
+
+	Target string
+
+	MasterTimeout       time.Duration
+	Timeout             time.Duration
+	WaitForActiveShards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesCloneRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_clone") + 1 + len(r.Target))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_clone")
+	path.WriteString("/")
+	path.WriteString(r.Target)
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForActiveShards != "" {
+		params["wait_for_active_shards"] = r.WaitForActiveShards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesClone) WithContext(v context.Context) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The configuration for the target index (`settings` and `aliases`).
+//
+func (f IndicesClone) WithBody(v io.Reader) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.Body = v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesClone) WithMasterTimeout(v time.Duration) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f IndicesClone) WithTimeout(v time.Duration) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForActiveShards - set the number of active shards to wait for on the cloned index before the operation returns..
+//
+func (f IndicesClone) WithWaitForActiveShards(v string) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.WaitForActiveShards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesClone) WithPretty() func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesClone) WithHuman() func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesClone) WithErrorTrace() func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesClone) WithFilterPath(v ...string) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesClone) WithHeader(h map[string]string) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesClone) WithOpaqueID(s string) func(*IndicesCloneRequest) {
+	return func(r *IndicesCloneRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.close.go b/esapi/api.indices.close.go
old mode 100755
new mode 100644
index 2913c25f39..7d6ebd6752
--- a/esapi/api.indices.close.go
+++ b/esapi/api.indices.close.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newIndicesCloseFunc(t Transport) IndicesClose {
 
 // IndicesClose closes an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html.
 //
 type IndicesClose func(index []string, o ...func(*IndicesCloseRequest)) (*Response, error)
 
@@ -32,17 +50,20 @@ type IndicesClose func(index []string, o ...func(*IndicesCloseRequest)) (*Respon
 type IndicesCloseRequest struct {
 	Index []string
 
-	AllowNoIndices    *bool
-	ExpandWildcards   string
-	IgnoreUnavailable *bool
-	MasterTimeout     time.Duration
-	Timeout           time.Duration
+	AllowNoIndices      *bool
+	ExpandWildcards     string
+	IgnoreUnavailable   *bool
+	MasterTimeout       time.Duration
+	Timeout             time.Duration
+	WaitForActiveShards string
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -85,6 +106,10 @@ func (r IndicesCloseRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["timeout"] = formatDuration(r.Timeout)
 	}
 
+	if r.WaitForActiveShards != "" {
+		params["wait_for_active_shards"] = r.WaitForActiveShards
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -101,7 +126,10 @@ func (r IndicesCloseRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -111,6 +139,18 @@ func (r IndicesCloseRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -177,6 +217,14 @@ func (f IndicesClose) WithTimeout(v time.Duration) func(*IndicesCloseRequest) {
 	}
 }
 
+// WithWaitForActiveShards - sets the number of active shards to wait for before the operation returns. set to `index-setting` to wait according to the index setting `index.write.wait_for_active_shards`, or `all` to wait for all shards, or an integer. defaults to `0`..
+//
+func (f IndicesClose) WithWaitForActiveShards(v string) func(*IndicesCloseRequest) {
+	return func(r *IndicesCloseRequest) {
+		r.WaitForActiveShards = v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f IndicesClose) WithPretty() func(*IndicesCloseRequest) {
@@ -208,3 +256,27 @@ func (f IndicesClose) WithFilterPath(v ...string) func(*IndicesCloseRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesClose) WithHeader(h map[string]string) func(*IndicesCloseRequest) {
+	return func(r *IndicesCloseRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesClose) WithOpaqueID(s string) func(*IndicesCloseRequest) {
+	return func(r *IndicesCloseRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.create.go b/esapi/api.indices.create.go
old mode 100755
new mode 100644
index 5e073fbbbd..7d55e47b2c
--- a/esapi/api.indices.create.go
+++ b/esapi/api.indices.create.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newIndicesCreateFunc(t Transport) IndicesCreate {
 
 // IndicesCreate creates an index with optional settings and mappings.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-create-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-create-index.html.
 //
 type IndicesCreate func(index string, o ...func(*IndicesCreateRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type IndicesCreate func(index string, o ...func(*IndicesCreateRequest)) (*Respon
 //
 type IndicesCreateRequest struct {
 	Index string
-	Body  io.Reader
+
+	Body io.Reader
 
 	IncludeTypeName     *bool
 	MasterTimeout       time.Duration
@@ -44,6 +63,8 @@ type IndicesCreateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -96,7 +117,10 @@ func (r IndicesCreateRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -110,6 +134,18 @@ func (r IndicesCreateRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -207,3 +243,27 @@ func (f IndicesCreate) WithFilterPath(v ...string) func(*IndicesCreateRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesCreate) WithHeader(h map[string]string) func(*IndicesCreateRequest) {
+	return func(r *IndicesCreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesCreate) WithOpaqueID(s string) func(*IndicesCreateRequest) {
+	return func(r *IndicesCreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.delete.go b/esapi/api.indices.delete.go
old mode 100755
new mode 100644
index 63c668a09d..fbd2fe9663
--- a/esapi/api.indices.delete.go
+++ b/esapi/api.indices.delete.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newIndicesDeleteFunc(t Transport) IndicesDelete {
 
 // IndicesDelete deletes an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-delete-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-delete-index.html.
 //
 type IndicesDelete func(index []string, o ...func(*IndicesDeleteRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type IndicesDeleteRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -99,7 +119,10 @@ func (r IndicesDeleteRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -109,6 +132,18 @@ func (r IndicesDeleteRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -143,7 +178,7 @@ func (f IndicesDelete) WithAllowNoIndices(v bool) func(*IndicesDeleteRequest) {
 	}
 }
 
-// WithExpandWildcards - whether wildcard expressions should get expanded to open or closed indices (default: open).
+// WithExpandWildcards - whether wildcard expressions should get expanded to open, closed, or hidden indices.
 //
 func (f IndicesDelete) WithExpandWildcards(v string) func(*IndicesDeleteRequest) {
 	return func(r *IndicesDeleteRequest) {
@@ -206,3 +241,27 @@ func (f IndicesDelete) WithFilterPath(v ...string) func(*IndicesDeleteRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDelete) WithHeader(h map[string]string) func(*IndicesDeleteRequest) {
+	return func(r *IndicesDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDelete) WithOpaqueID(s string) func(*IndicesDeleteRequest) {
+	return func(r *IndicesDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.delete_alias.go b/esapi/api.indices.delete_alias.go
old mode 100755
new mode 100644
index a9032b91b9..696f9e4436
--- a/esapi/api.indices.delete_alias.go
+++ b/esapi/api.indices.delete_alias.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,16 +40,17 @@ func newIndicesDeleteAliasFunc(t Transport) IndicesDeleteAlias {
 
 // IndicesDeleteAlias deletes an alias.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
 //
 type IndicesDeleteAlias func(index []string, name []string, o ...func(*IndicesDeleteAliasRequest)) (*Response, error)
 
-// IndicesDeleteAliasRequest configures the Indices  Delete Alias API request.
+// IndicesDeleteAliasRequest configures the Indices Delete Alias API request.
 //
 type IndicesDeleteAliasRequest struct {
 	Index []string
 
-	Name          []string
+	Name []string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -40,6 +59,8 @@ type IndicesDeleteAliasRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -88,7 +109,10 @@ func (r IndicesDeleteAliasRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -98,6 +122,18 @@ func (r IndicesDeleteAliasRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -171,3 +207,27 @@ func (f IndicesDeleteAlias) WithFilterPath(v ...string) func(*IndicesDeleteAlias
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDeleteAlias) WithHeader(h map[string]string) func(*IndicesDeleteAliasRequest) {
+	return func(r *IndicesDeleteAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDeleteAlias) WithOpaqueID(s string) func(*IndicesDeleteAliasRequest) {
+	return func(r *IndicesDeleteAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.delete_index_template.go b/esapi/api.indices.delete_index_template.go
new file mode 100644
index 0000000000..ef8b622463
--- /dev/null
+++ b/esapi/api.indices.delete_index_template.go
@@ -0,0 +1,229 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newIndicesDeleteIndexTemplateFunc(t Transport) IndicesDeleteIndexTemplate {
+	return func(name string, o ...func(*IndicesDeleteIndexTemplateRequest)) (*Response, error) {
+		var r = IndicesDeleteIndexTemplateRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesDeleteIndexTemplate deletes an index template.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesDeleteIndexTemplate func(name string, o ...func(*IndicesDeleteIndexTemplateRequest)) (*Response, error)
+
+// IndicesDeleteIndexTemplateRequest configures the Indices Delete Index Template API request.
+//
+type IndicesDeleteIndexTemplateRequest struct {
+	Name string
+
+	MasterTimeout time.Duration
+	Timeout       time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesDeleteIndexTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_index_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesDeleteIndexTemplate) WithContext(v context.Context) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesDeleteIndexTemplate) WithMasterTimeout(v time.Duration) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f IndicesDeleteIndexTemplate) WithTimeout(v time.Duration) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesDeleteIndexTemplate) WithPretty() func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesDeleteIndexTemplate) WithHuman() func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesDeleteIndexTemplate) WithErrorTrace() func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesDeleteIndexTemplate) WithFilterPath(v ...string) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDeleteIndexTemplate) WithHeader(h map[string]string) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDeleteIndexTemplate) WithOpaqueID(s string) func(*IndicesDeleteIndexTemplateRequest) {
+	return func(r *IndicesDeleteIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.delete_template.go b/esapi/api.indices.delete_template.go
old mode 100755
new mode 100644
index ebde1db3a6..c40d2d9f7b
--- a/esapi/api.indices.delete_template.go
+++ b/esapi/api.indices.delete_template.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,14 +40,15 @@ func newIndicesDeleteTemplateFunc(t Transport) IndicesDeleteTemplate {
 
 // IndicesDeleteTemplate deletes an index template.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
 //
 type IndicesDeleteTemplate func(name string, o ...func(*IndicesDeleteTemplateRequest)) (*Response, error)
 
-// IndicesDeleteTemplateRequest configures the Indices  Delete Template API request.
+// IndicesDeleteTemplateRequest configures the Indices Delete Template API request.
 //
 type IndicesDeleteTemplateRequest struct {
-	Name          string
+	Name string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -38,6 +57,8 @@ type IndicesDeleteTemplateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -84,7 +105,10 @@ func (r IndicesDeleteTemplateRequest) Do(ctx context.Context, transport Transpor
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -94,6 +118,18 @@ func (r IndicesDeleteTemplateRequest) Do(ctx context.Context, transport Transpor
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -167,3 +203,27 @@ func (f IndicesDeleteTemplate) WithFilterPath(v ...string) func(*IndicesDeleteTe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDeleteTemplate) WithHeader(h map[string]string) func(*IndicesDeleteTemplateRequest) {
+	return func(r *IndicesDeleteTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDeleteTemplate) WithOpaqueID(s string) func(*IndicesDeleteTemplateRequest) {
+	return func(r *IndicesDeleteTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.disk_usage.go b/esapi/api.indices.disk_usage.go
new file mode 100644
index 0000000000..cc84d103bd
--- /dev/null
+++ b/esapi/api.indices.disk_usage.go
@@ -0,0 +1,270 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newIndicesDiskUsageFunc(t Transport) IndicesDiskUsage {
+	return func(index string, o ...func(*IndicesDiskUsageRequest)) (*Response, error) {
+		var r = IndicesDiskUsageRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesDiskUsage analyzes the disk usage of each field of an index or data stream
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-disk-usage.html.
+//
+type IndicesDiskUsage func(index string, o ...func(*IndicesDiskUsageRequest)) (*Response, error)
+
+// IndicesDiskUsageRequest configures the Indices Disk Usage API request.
+//
+type IndicesDiskUsageRequest struct {
+	Index string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	Flush             *bool
+	IgnoreUnavailable *bool
+	RunExpensiveTasks *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesDiskUsageRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_disk_usage"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_disk_usage")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.Flush != nil {
+		params["flush"] = strconv.FormatBool(*r.Flush)
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.RunExpensiveTasks != nil {
+		params["run_expensive_tasks"] = strconv.FormatBool(*r.RunExpensiveTasks)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesDiskUsage) WithContext(v context.Context) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesDiskUsage) WithAllowNoIndices(v bool) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesDiskUsage) WithExpandWildcards(v string) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithFlush - whether flush or not before analyzing the index disk usage. defaults to true.
+//
+func (f IndicesDiskUsage) WithFlush(v bool) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.Flush = &v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesDiskUsage) WithIgnoreUnavailable(v bool) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithRunExpensiveTasks - must be set to [true] in order for the task to be performed. defaults to false..
+//
+func (f IndicesDiskUsage) WithRunExpensiveTasks(v bool) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.RunExpensiveTasks = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesDiskUsage) WithPretty() func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesDiskUsage) WithHuman() func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesDiskUsage) WithErrorTrace() func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesDiskUsage) WithFilterPath(v ...string) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDiskUsage) WithHeader(h map[string]string) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDiskUsage) WithOpaqueID(s string) func(*IndicesDiskUsageRequest) {
+	return func(r *IndicesDiskUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.exists.go b/esapi/api.indices.exists.go
old mode 100755
new mode 100644
index 07310f5a86..a6335f6d1b
--- a/esapi/api.indices.exists.go
+++ b/esapi/api.indices.exists.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesExistsFunc(t Transport) IndicesExists {
 
 // IndicesExists returns information about whether a particular index exists.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-exists.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-exists.html.
 //
 type IndicesExists func(index []string, o ...func(*IndicesExistsRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type IndicesExistsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -103,7 +123,10 @@ func (r IndicesExistsRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -113,6 +136,18 @@ func (r IndicesExistsRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -218,3 +253,27 @@ func (f IndicesExists) WithFilterPath(v ...string) func(*IndicesExistsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesExists) WithHeader(h map[string]string) func(*IndicesExistsRequest) {
+	return func(r *IndicesExistsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesExists) WithOpaqueID(s string) func(*IndicesExistsRequest) {
+	return func(r *IndicesExistsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.exists_alias.go b/esapi/api.indices.exists_alias.go
old mode 100755
new mode 100644
index b3a3fb1e03..edc78bdddc
--- a/esapi/api.indices.exists_alias.go
+++ b/esapi/api.indices.exists_alias.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,16 +40,17 @@ func newIndicesExistsAliasFunc(t Transport) IndicesExistsAlias {
 
 // IndicesExistsAlias returns information about whether a particular alias exists.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
 //
 type IndicesExistsAlias func(name []string, o ...func(*IndicesExistsAliasRequest)) (*Response, error)
 
-// IndicesExistsAliasRequest configures the Indices  Exists Alias API request.
+// IndicesExistsAliasRequest configures the Indices Exists Alias API request.
 //
 type IndicesExistsAliasRequest struct {
 	Index []string
 
-	Name              []string
+	Name []string
+
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	IgnoreUnavailable *bool
@@ -42,6 +61,8 @@ type IndicesExistsAliasRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -100,7 +121,10 @@ func (r IndicesExistsAliasRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -110,6 +134,18 @@ func (r IndicesExistsAliasRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -207,3 +243,27 @@ func (f IndicesExistsAlias) WithFilterPath(v ...string) func(*IndicesExistsAlias
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesExistsAlias) WithHeader(h map[string]string) func(*IndicesExistsAliasRequest) {
+	return func(r *IndicesExistsAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesExistsAlias) WithOpaqueID(s string) func(*IndicesExistsAliasRequest) {
+	return func(r *IndicesExistsAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.exists_index_template.go b/esapi/api.indices.exists_index_template.go
new file mode 100644
index 0000000000..dd160e3a67
--- /dev/null
+++ b/esapi/api.indices.exists_index_template.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesExistsIndexTemplateFunc(t Transport) IndicesExistsIndexTemplate {
+	return func(name string, o ...func(*IndicesExistsIndexTemplateRequest)) (*Response, error) {
+		var r = IndicesExistsIndexTemplateRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesExistsIndexTemplate returns information about whether a particular index template exists.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesExistsIndexTemplate func(name string, o ...func(*IndicesExistsIndexTemplateRequest)) (*Response, error)
+
+// IndicesExistsIndexTemplateRequest configures the Indices Exists Index Template API request.
+//
+type IndicesExistsIndexTemplateRequest struct {
+	Name string
+
+	FlatSettings  *bool
+	Local         *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesExistsIndexTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "HEAD"
+
+	path.Grow(1 + len("_index_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.FlatSettings != nil {
+		params["flat_settings"] = strconv.FormatBool(*r.FlatSettings)
+	}
+
+	if r.Local != nil {
+		params["local"] = strconv.FormatBool(*r.Local)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesExistsIndexTemplate) WithContext(v context.Context) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithFlatSettings - return settings in flat format (default: false).
+//
+func (f IndicesExistsIndexTemplate) WithFlatSettings(v bool) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.FlatSettings = &v
+	}
+}
+
+// WithLocal - return local information, do not retrieve the state from master node (default: false).
+//
+func (f IndicesExistsIndexTemplate) WithLocal(v bool) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.Local = &v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f IndicesExistsIndexTemplate) WithMasterTimeout(v time.Duration) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesExistsIndexTemplate) WithPretty() func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesExistsIndexTemplate) WithHuman() func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesExistsIndexTemplate) WithErrorTrace() func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesExistsIndexTemplate) WithFilterPath(v ...string) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesExistsIndexTemplate) WithHeader(h map[string]string) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesExistsIndexTemplate) WithOpaqueID(s string) func(*IndicesExistsIndexTemplateRequest) {
+	return func(r *IndicesExistsIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.exists_template.go b/esapi/api.indices.exists_template.go
old mode 100755
new mode 100644
index 2e1fedcb57..b5f798cd01
--- a/esapi/api.indices.exists_template.go
+++ b/esapi/api.indices.exists_template.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newIndicesExistsTemplateFunc(t Transport) IndicesExistsTemplate {
 
 // IndicesExistsTemplate returns information about whether a particular index template exists.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
 //
 type IndicesExistsTemplate func(name []string, o ...func(*IndicesExistsTemplateRequest)) (*Response, error)
 
-// IndicesExistsTemplateRequest configures the Indices  Exists Template API request.
+// IndicesExistsTemplateRequest configures the Indices Exists Template API request.
 //
 type IndicesExistsTemplateRequest struct {
-	Name          []string
+	Name []string
+
 	FlatSettings  *bool
 	Local         *bool
 	MasterTimeout time.Duration
@@ -40,6 +59,8 @@ type IndicesExistsTemplateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -90,7 +111,10 @@ func (r IndicesExistsTemplateRequest) Do(ctx context.Context, transport Transpor
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -100,6 +124,18 @@ func (r IndicesExistsTemplateRequest) Do(ctx context.Context, transport Transpor
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -181,3 +217,27 @@ func (f IndicesExistsTemplate) WithFilterPath(v ...string) func(*IndicesExistsTe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesExistsTemplate) WithHeader(h map[string]string) func(*IndicesExistsTemplateRequest) {
+	return func(r *IndicesExistsTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesExistsTemplate) WithOpaqueID(s string) func(*IndicesExistsTemplateRequest) {
+	return func(r *IndicesExistsTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.exists_type.go b/esapi/api.indices.exists_type.go
old mode 100755
new mode 100644
index 0c8ea9c8bc..11e91e54d1
--- a/esapi/api.indices.exists_type.go
+++ b/esapi/api.indices.exists_type.go
@@ -1,16 +1,34 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
 
-func newIndicesExistsTypeFunc(t Transport) IndicesExistsType {
-	return func(index []string, o ...func(*IndicesExistsTypeRequest)) (*Response, error) {
-		var r = IndicesExistsTypeRequest{Index: index}
+func newIndicesExistsDocumentTypeFunc(t Transport) IndicesExistsDocumentType {
+	return func(index []string, o ...func(*IndicesExistsDocumentTypeRequest)) (*Response, error) {
+		var r = IndicesExistsDocumentTypeRequest{Index: index}
 		for _, f := range o {
 			f(&r)
 		}
@@ -20,15 +38,15 @@ func newIndicesExistsTypeFunc(t Transport) IndicesExistsType {
 
 // ----- API Definition -------------------------------------------------------
 
-// IndicesExistsType returns information about whether a particular document type exists. (DEPRECATED)
+// IndicesExistsDocumentType returns information about whether a particular document type exists. (DEPRECATED)
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-types-exists.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-types-exists.html.
 //
-type IndicesExistsType func(index []string, o ...func(*IndicesExistsTypeRequest)) (*Response, error)
+type IndicesExistsDocumentType func(index []string, o ...func(*IndicesExistsDocumentTypeRequest)) (*Response, error)
 
-// IndicesExistsTypeRequest configures the Indices  Exists Type API request.
+// IndicesExistsDocumentTypeRequest configures the Indices Exists Document Type API request.
 //
-type IndicesExistsTypeRequest struct {
+type IndicesExistsDocumentTypeRequest struct {
 	Index        []string
 	DocumentType []string
 
@@ -42,12 +60,14 @@ type IndicesExistsTypeRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
 // Do executes the request and returns response or error.
 //
-func (r IndicesExistsTypeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+func (r IndicesExistsDocumentTypeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
 	var (
 		method string
 		path   strings.Builder
@@ -98,7 +118,10 @@ func (r IndicesExistsTypeRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -108,6 +131,18 @@ func (r IndicesExistsTypeRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -128,80 +163,104 @@ func (r IndicesExistsTypeRequest) Do(ctx context.Context, transport Transport) (
 
 // WithContext sets the request context.
 //
-func (f IndicesExistsType) WithContext(v context.Context) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithContext(v context.Context) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.ctx = v
 	}
 }
 
 // WithDocumentType - a list of document types to check.
 //
-func (f IndicesExistsType) WithDocumentType(v ...string) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithDocumentType(v ...string) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.DocumentType = v
 	}
 }
 
 // WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
 //
-func (f IndicesExistsType) WithAllowNoIndices(v bool) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithAllowNoIndices(v bool) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.AllowNoIndices = &v
 	}
 }
 
 // WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
 //
-func (f IndicesExistsType) WithExpandWildcards(v string) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithExpandWildcards(v string) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.ExpandWildcards = v
 	}
 }
 
 // WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
 //
-func (f IndicesExistsType) WithIgnoreUnavailable(v bool) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithIgnoreUnavailable(v bool) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.IgnoreUnavailable = &v
 	}
 }
 
 // WithLocal - return local information, do not retrieve the state from master node (default: false).
 //
-func (f IndicesExistsType) WithLocal(v bool) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithLocal(v bool) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.Local = &v
 	}
 }
 
 // WithPretty makes the response body pretty-printed.
 //
-func (f IndicesExistsType) WithPretty() func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithPretty() func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.Pretty = true
 	}
 }
 
 // WithHuman makes statistical values human-readable.
 //
-func (f IndicesExistsType) WithHuman() func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithHuman() func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.Human = true
 	}
 }
 
 // WithErrorTrace includes the stack trace for errors in the response body.
 //
-func (f IndicesExistsType) WithErrorTrace() func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithErrorTrace() func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.ErrorTrace = true
 	}
 }
 
 // WithFilterPath filters the properties of the response body.
 //
-func (f IndicesExistsType) WithFilterPath(v ...string) func(*IndicesExistsTypeRequest) {
-	return func(r *IndicesExistsTypeRequest) {
+func (f IndicesExistsDocumentType) WithFilterPath(v ...string) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesExistsDocumentType) WithHeader(h map[string]string) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesExistsDocumentType) WithOpaqueID(s string) func(*IndicesExistsDocumentTypeRequest) {
+	return func(r *IndicesExistsDocumentTypeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.field_usage_stats.go b/esapi/api.indices.field_usage_stats.go
new file mode 100644
index 0000000000..b221910c44
--- /dev/null
+++ b/esapi/api.indices.field_usage_stats.go
@@ -0,0 +1,257 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newIndicesFieldUsageStatsFunc(t Transport) IndicesFieldUsageStats {
+	return func(index string, o ...func(*IndicesFieldUsageStatsRequest)) (*Response, error) {
+		var r = IndicesFieldUsageStatsRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesFieldUsageStats returns the field usage stats for each field of an index
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/field-usage-stats.html.
+//
+type IndicesFieldUsageStats func(index string, o ...func(*IndicesFieldUsageStatsRequest)) (*Response, error)
+
+// IndicesFieldUsageStatsRequest configures the Indices Field Usage Stats API request.
+//
+type IndicesFieldUsageStatsRequest struct {
+	Index string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	Fields            []string
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesFieldUsageStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_field_usage_stats"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_field_usage_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if len(r.Fields) > 0 {
+		params["fields"] = strings.Join(r.Fields, ",")
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesFieldUsageStats) WithContext(v context.Context) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesFieldUsageStats) WithAllowNoIndices(v bool) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesFieldUsageStats) WithExpandWildcards(v string) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithFields - a list of fields to include in the stats if only a subset of fields should be returned (supports wildcards).
+//
+func (f IndicesFieldUsageStats) WithFields(v ...string) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.Fields = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesFieldUsageStats) WithIgnoreUnavailable(v bool) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesFieldUsageStats) WithPretty() func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesFieldUsageStats) WithHuman() func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesFieldUsageStats) WithErrorTrace() func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesFieldUsageStats) WithFilterPath(v ...string) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesFieldUsageStats) WithHeader(h map[string]string) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesFieldUsageStats) WithOpaqueID(s string) func(*IndicesFieldUsageStatsRequest) {
+	return func(r *IndicesFieldUsageStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.flush.go b/esapi/api.indices.flush.go
old mode 100755
new mode 100644
index 353bc1ac8a..34620a8732
--- a/esapi/api.indices.flush.go
+++ b/esapi/api.indices.flush.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesFlushFunc(t Transport) IndicesFlush {
 
 // IndicesFlush performs the flush operation on one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-flush.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-flush.html.
 //
 type IndicesFlush func(o ...func(*IndicesFlushRequest)) (*Response, error)
 
@@ -42,6 +60,8 @@ type IndicesFlushRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -102,7 +122,10 @@ func (r IndicesFlushRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -112,6 +135,18 @@ func (r IndicesFlushRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -217,3 +252,27 @@ func (f IndicesFlush) WithFilterPath(v ...string) func(*IndicesFlushRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesFlush) WithHeader(h map[string]string) func(*IndicesFlushRequest) {
+	return func(r *IndicesFlushRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesFlush) WithOpaqueID(s string) func(*IndicesFlushRequest) {
+	return func(r *IndicesFlushRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.flush_synced.go b/esapi/api.indices.flush_synced.go
old mode 100755
new mode 100644
index 975d3d7203..eb72ac1538
--- a/esapi/api.indices.flush_synced.go
+++ b/esapi/api.indices.flush_synced.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -20,13 +38,13 @@ func newIndicesFlushSyncedFunc(t Transport) IndicesFlushSynced {
 
 // ----- API Definition -------------------------------------------------------
 
-// IndicesFlushSynced performs a synced flush operation on one or more indices.
+// IndicesFlushSynced performs a synced flush operation on one or more indices. Synced flush is deprecated and will be removed in 8.0. Use flush instead
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-synced-flush.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-synced-flush-api.html.
 //
 type IndicesFlushSynced func(o ...func(*IndicesFlushSyncedRequest)) (*Response, error)
 
-// IndicesFlushSyncedRequest configures the Indices  Flush Synced API request.
+// IndicesFlushSyncedRequest configures the Indices Flush Synced API request.
 //
 type IndicesFlushSyncedRequest struct {
 	Index []string
@@ -40,6 +58,8 @@ type IndicesFlushSyncedRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -94,7 +114,10 @@ func (r IndicesFlushSyncedRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -104,6 +127,18 @@ func (r IndicesFlushSyncedRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -193,3 +228,27 @@ func (f IndicesFlushSynced) WithFilterPath(v ...string) func(*IndicesFlushSynced
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesFlushSynced) WithHeader(h map[string]string) func(*IndicesFlushSyncedRequest) {
+	return func(r *IndicesFlushSyncedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesFlushSynced) WithOpaqueID(s string) func(*IndicesFlushSyncedRequest) {
+	return func(r *IndicesFlushSyncedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.forcemerge.go b/esapi/api.indices.forcemerge.go
old mode 100755
new mode 100644
index 71e8a0ebe0..69062e1cc6
--- a/esapi/api.indices.forcemerge.go
+++ b/esapi/api.indices.forcemerge.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesForcemergeFunc(t Transport) IndicesForcemerge {
 
 // IndicesForcemerge performs the force merge operation on one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-forcemerge.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-forcemerge.html.
 //
 type IndicesForcemerge func(o ...func(*IndicesForcemergeRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type IndicesForcemergeRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -107,7 +127,10 @@ func (r IndicesForcemergeRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -117,6 +140,18 @@ func (r IndicesForcemergeRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -230,3 +265,27 @@ func (f IndicesForcemerge) WithFilterPath(v ...string) func(*IndicesForcemergeRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesForcemerge) WithHeader(h map[string]string) func(*IndicesForcemergeRequest) {
+	return func(r *IndicesForcemergeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesForcemerge) WithOpaqueID(s string) func(*IndicesForcemergeRequest) {
+	return func(r *IndicesForcemergeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get.go b/esapi/api.indices.get.go
old mode 100755
new mode 100644
index c37ece21de..9aec2f5f6d
--- a/esapi/api.indices.get.go
+++ b/esapi/api.indices.get.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newIndicesGetFunc(t Transport) IndicesGet {
 
 // IndicesGet returns information about one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-index.html.
 //
 type IndicesGet func(index []string, o ...func(*IndicesGetRequest)) (*Response, error)
 
@@ -46,6 +64,8 @@ type IndicesGetRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -114,7 +134,10 @@ func (r IndicesGetRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -124,6 +147,18 @@ func (r IndicesGetRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -245,3 +280,27 @@ func (f IndicesGet) WithFilterPath(v ...string) func(*IndicesGetRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGet) WithHeader(h map[string]string) func(*IndicesGetRequest) {
+	return func(r *IndicesGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGet) WithOpaqueID(s string) func(*IndicesGetRequest) {
+	return func(r *IndicesGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_alias.go b/esapi/api.indices.get_alias.go
old mode 100755
new mode 100644
index 36bd7df573..10e1bcdbfc
--- a/esapi/api.indices.get_alias.go
+++ b/esapi/api.indices.get_alias.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,16 +40,17 @@ func newIndicesGetAliasFunc(t Transport) IndicesGetAlias {
 
 // IndicesGetAlias returns an alias.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
 //
 type IndicesGetAlias func(o ...func(*IndicesGetAliasRequest)) (*Response, error)
 
-// IndicesGetAliasRequest configures the Indices  Get Alias API request.
+// IndicesGetAliasRequest configures the Indices Get Alias API request.
 //
 type IndicesGetAliasRequest struct {
 	Index []string
 
-	Name              []string
+	Name []string
+
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	IgnoreUnavailable *bool
@@ -42,6 +61,8 @@ type IndicesGetAliasRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -102,7 +123,10 @@ func (r IndicesGetAliasRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -112,6 +136,18 @@ func (r IndicesGetAliasRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -217,3 +253,27 @@ func (f IndicesGetAlias) WithFilterPath(v ...string) func(*IndicesGetAliasReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetAlias) WithHeader(h map[string]string) func(*IndicesGetAliasRequest) {
+	return func(r *IndicesGetAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetAlias) WithOpaqueID(s string) func(*IndicesGetAliasRequest) {
+	return func(r *IndicesGetAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_field_mapping.go b/esapi/api.indices.get_field_mapping.go
old mode 100755
new mode 100644
index b4e34084d2..278c46b86c
--- a/esapi/api.indices.get_field_mapping.go
+++ b/esapi/api.indices.get_field_mapping.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,17 +40,18 @@ func newIndicesGetFieldMappingFunc(t Transport) IndicesGetFieldMapping {
 
 // IndicesGetFieldMapping returns mapping for one or more fields.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-field-mapping.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-field-mapping.html.
 //
 type IndicesGetFieldMapping func(fields []string, o ...func(*IndicesGetFieldMappingRequest)) (*Response, error)
 
-// IndicesGetFieldMappingRequest configures the Indices   Get Field Mapping API request.
+// IndicesGetFieldMappingRequest configures the Indices Get Field Mapping API request.
 //
 type IndicesGetFieldMappingRequest struct {
 	Index        []string
 	DocumentType []string
 
-	Fields            []string
+	Fields []string
+
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	IgnoreUnavailable *bool
@@ -45,6 +64,8 @@ type IndicesGetFieldMappingRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -117,7 +138,10 @@ func (r IndicesGetFieldMappingRequest) Do(ctx context.Context, transport Transpo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -127,6 +151,18 @@ func (r IndicesGetFieldMappingRequest) Do(ctx context.Context, transport Transpo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -248,3 +284,27 @@ func (f IndicesGetFieldMapping) WithFilterPath(v ...string) func(*IndicesGetFiel
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetFieldMapping) WithHeader(h map[string]string) func(*IndicesGetFieldMappingRequest) {
+	return func(r *IndicesGetFieldMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetFieldMapping) WithOpaqueID(s string) func(*IndicesGetFieldMappingRequest) {
+	return func(r *IndicesGetFieldMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_index_template.go b/esapi/api.indices.get_index_template.go
new file mode 100644
index 0000000000..a0279fd528
--- /dev/null
+++ b/esapi/api.indices.get_index_template.go
@@ -0,0 +1,253 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesGetIndexTemplateFunc(t Transport) IndicesGetIndexTemplate {
+	return func(o ...func(*IndicesGetIndexTemplateRequest)) (*Response, error) {
+		var r = IndicesGetIndexTemplateRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesGetIndexTemplate returns an index template.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesGetIndexTemplate func(o ...func(*IndicesGetIndexTemplateRequest)) (*Response, error)
+
+// IndicesGetIndexTemplateRequest configures the Indices Get Index Template API request.
+//
+type IndicesGetIndexTemplateRequest struct {
+	Name string
+
+	FlatSettings  *bool
+	Local         *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesGetIndexTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_index_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	if r.Name != "" {
+		path.WriteString("/")
+		path.WriteString(r.Name)
+	}
+
+	params = make(map[string]string)
+
+	if r.FlatSettings != nil {
+		params["flat_settings"] = strconv.FormatBool(*r.FlatSettings)
+	}
+
+	if r.Local != nil {
+		params["local"] = strconv.FormatBool(*r.Local)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesGetIndexTemplate) WithContext(v context.Context) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a pattern that returned template names must match.
+//
+func (f IndicesGetIndexTemplate) WithName(v string) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.Name = v
+	}
+}
+
+// WithFlatSettings - return settings in flat format (default: false).
+//
+func (f IndicesGetIndexTemplate) WithFlatSettings(v bool) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.FlatSettings = &v
+	}
+}
+
+// WithLocal - return local information, do not retrieve the state from master node (default: false).
+//
+func (f IndicesGetIndexTemplate) WithLocal(v bool) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.Local = &v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f IndicesGetIndexTemplate) WithMasterTimeout(v time.Duration) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesGetIndexTemplate) WithPretty() func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesGetIndexTemplate) WithHuman() func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesGetIndexTemplate) WithErrorTrace() func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesGetIndexTemplate) WithFilterPath(v ...string) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetIndexTemplate) WithHeader(h map[string]string) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetIndexTemplate) WithOpaqueID(s string) func(*IndicesGetIndexTemplateRequest) {
+	return func(r *IndicesGetIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_mapping.go b/esapi/api.indices.get_mapping.go
old mode 100755
new mode 100644
index 423591046f..dc01738dd5
--- a/esapi/api.indices.get_mapping.go
+++ b/esapi/api.indices.get_mapping.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,11 +41,11 @@ func newIndicesGetMappingFunc(t Transport) IndicesGetMapping {
 
 // IndicesGetMapping returns mappings for one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-mapping.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-mapping.html.
 //
 type IndicesGetMapping func(o ...func(*IndicesGetMappingRequest)) (*Response, error)
 
-// IndicesGetMappingRequest configures the Indices  Get Mapping API request.
+// IndicesGetMappingRequest configures the Indices Get Mapping API request.
 //
 type IndicesGetMappingRequest struct {
 	Index        []string
@@ -45,6 +63,8 @@ type IndicesGetMappingRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -113,7 +133,10 @@ func (r IndicesGetMappingRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -123,6 +146,18 @@ func (r IndicesGetMappingRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -244,3 +279,27 @@ func (f IndicesGetMapping) WithFilterPath(v ...string) func(*IndicesGetMappingRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetMapping) WithHeader(h map[string]string) func(*IndicesGetMappingRequest) {
+	return func(r *IndicesGetMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetMapping) WithOpaqueID(s string) func(*IndicesGetMappingRequest) {
+	return func(r *IndicesGetMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_settings.go b/esapi/api.indices.get_settings.go
old mode 100755
new mode 100644
index 9e0ad75f34..eb28363799
--- a/esapi/api.indices.get_settings.go
+++ b/esapi/api.indices.get_settings.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,16 +41,17 @@ func newIndicesGetSettingsFunc(t Transport) IndicesGetSettings {
 
 // IndicesGetSettings returns settings for one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-settings.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-get-settings.html.
 //
 type IndicesGetSettings func(o ...func(*IndicesGetSettingsRequest)) (*Response, error)
 
-// IndicesGetSettingsRequest configures the Indices  Get Settings API request.
+// IndicesGetSettingsRequest configures the Indices Get Settings API request.
 //
 type IndicesGetSettingsRequest struct {
 	Index []string
 
-	Name              []string
+	Name []string
+
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	FlatSettings      *bool
@@ -46,6 +65,8 @@ type IndicesGetSettingsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -118,7 +139,10 @@ func (r IndicesGetSettingsRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -128,6 +152,18 @@ func (r IndicesGetSettingsRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -257,3 +293,27 @@ func (f IndicesGetSettings) WithFilterPath(v ...string) func(*IndicesGetSettings
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetSettings) WithHeader(h map[string]string) func(*IndicesGetSettingsRequest) {
+	return func(r *IndicesGetSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetSettings) WithOpaqueID(s string) func(*IndicesGetSettingsRequest) {
+	return func(r *IndicesGetSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_template.go b/esapi/api.indices.get_template.go
old mode 100755
new mode 100644
index 13c4b263c4..12e0a3d8c0
--- a/esapi/api.indices.get_template.go
+++ b/esapi/api.indices.get_template.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newIndicesGetTemplateFunc(t Transport) IndicesGetTemplate {
 
 // IndicesGetTemplate returns an index template.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
 //
 type IndicesGetTemplate func(o ...func(*IndicesGetTemplateRequest)) (*Response, error)
 
-// IndicesGetTemplateRequest configures the Indices  Get Template API request.
+// IndicesGetTemplateRequest configures the Indices Get Template API request.
 //
 type IndicesGetTemplateRequest struct {
-	Name            []string
+	Name []string
+
 	FlatSettings    *bool
 	IncludeTypeName *bool
 	Local           *bool
@@ -41,6 +60,8 @@ type IndicesGetTemplateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -97,7 +118,10 @@ func (r IndicesGetTemplateRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +131,18 @@ func (r IndicesGetTemplateRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -204,3 +240,27 @@ func (f IndicesGetTemplate) WithFilterPath(v ...string) func(*IndicesGetTemplate
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetTemplate) WithHeader(h map[string]string) func(*IndicesGetTemplateRequest) {
+	return func(r *IndicesGetTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetTemplate) WithOpaqueID(s string) func(*IndicesGetTemplateRequest) {
+	return func(r *IndicesGetTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.get_upgrade.go b/esapi/api.indices.get_upgrade.go
old mode 100755
new mode 100644
index 969fbbe2f6..7babe63503
--- a/esapi/api.indices.get_upgrade.go
+++ b/esapi/api.indices.get_upgrade.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -20,13 +38,13 @@ func newIndicesGetUpgradeFunc(t Transport) IndicesGetUpgrade {
 
 // ----- API Definition -------------------------------------------------------
 
-// IndicesGetUpgrade the _upgrade API is no longer useful and will be removed.
+// IndicesGetUpgrade deprecated Returns a progress status of current upgrade.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-upgrade.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-upgrade.html.
 //
 type IndicesGetUpgrade func(o ...func(*IndicesGetUpgradeRequest)) (*Response, error)
 
-// IndicesGetUpgradeRequest configures the Indices  Get Upgrade API request.
+// IndicesGetUpgradeRequest configures the Indices Get Upgrade API request.
 //
 type IndicesGetUpgradeRequest struct {
 	Index []string
@@ -40,6 +58,8 @@ type IndicesGetUpgradeRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -92,7 +112,10 @@ func (r IndicesGetUpgradeRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -102,6 +125,18 @@ func (r IndicesGetUpgradeRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,3 +226,27 @@ func (f IndicesGetUpgrade) WithFilterPath(v ...string) func(*IndicesGetUpgradeRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetUpgrade) WithHeader(h map[string]string) func(*IndicesGetUpgradeRequest) {
+	return func(r *IndicesGetUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetUpgrade) WithOpaqueID(s string) func(*IndicesGetUpgradeRequest) {
+	return func(r *IndicesGetUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.modify_data_stream.go b/esapi/api.indices.modify_data_stream.go
new file mode 100644
index 0000000000..9178239ffc
--- /dev/null
+++ b/esapi/api.indices.modify_data_stream.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newIndicesModifyDataStreamFunc(t Transport) IndicesModifyDataStream {
+	return func(body io.Reader, o ...func(*IndicesModifyDataStreamRequest)) (*Response, error) {
+		var r = IndicesModifyDataStreamRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesModifyDataStream modifies a data stream
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesModifyDataStream func(body io.Reader, o ...func(*IndicesModifyDataStreamRequest)) (*Response, error)
+
+// IndicesModifyDataStreamRequest configures the Indices Modify Data Stream API request.
+//
+type IndicesModifyDataStreamRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesModifyDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_data_stream/_modify"))
+	path.WriteString("/_data_stream/_modify")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesModifyDataStream) WithContext(v context.Context) func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesModifyDataStream) WithPretty() func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesModifyDataStream) WithHuman() func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesModifyDataStream) WithErrorTrace() func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesModifyDataStream) WithFilterPath(v ...string) func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesModifyDataStream) WithHeader(h map[string]string) func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesModifyDataStream) WithOpaqueID(s string) func(*IndicesModifyDataStreamRequest) {
+	return func(r *IndicesModifyDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.open.go b/esapi/api.indices.open.go
old mode 100755
new mode 100644
index 8e47e6e8c1..9720cf7ded
--- a/esapi/api.indices.open.go
+++ b/esapi/api.indices.open.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,7 @@ func newIndicesOpenFunc(t Transport) IndicesOpen {
 
 // IndicesOpen opens an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html.
 //
 type IndicesOpen func(index []string, o ...func(*IndicesOpenRequest)) (*Response, error)
 
@@ -44,6 +62,8 @@ type IndicesOpenRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -106,7 +126,10 @@ func (r IndicesOpenRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +139,18 @@ func (r IndicesOpenRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -221,3 +256,27 @@ func (f IndicesOpen) WithFilterPath(v ...string) func(*IndicesOpenRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesOpen) WithHeader(h map[string]string) func(*IndicesOpenRequest) {
+	return func(r *IndicesOpenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesOpen) WithOpaqueID(s string) func(*IndicesOpenRequest) {
+	return func(r *IndicesOpenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.put_alias.go b/esapi/api.indices.put_alias.go
old mode 100755
new mode 100644
index 419fb9466d..d6e9ef4478
--- a/esapi/api.indices.put_alias.go
+++ b/esapi/api.indices.put_alias.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -23,17 +41,19 @@ func newIndicesPutAliasFunc(t Transport) IndicesPutAlias {
 
 // IndicesPutAlias creates or updates an alias.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
 //
 type IndicesPutAlias func(index []string, name string, o ...func(*IndicesPutAliasRequest)) (*Response, error)
 
-// IndicesPutAliasRequest configures the Indices  Put Alias API request.
+// IndicesPutAliasRequest configures the Indices Put Alias API request.
 //
 type IndicesPutAliasRequest struct {
 	Index []string
-	Body  io.Reader
 
-	Name          string
+	Body io.Reader
+
+	Name string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -42,6 +62,8 @@ type IndicesPutAliasRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -90,7 +112,10 @@ func (r IndicesPutAliasRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -104,6 +129,18 @@ func (r IndicesPutAliasRequest) Do(ctx context.Context, transport Transport) (*R
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -185,3 +222,27 @@ func (f IndicesPutAlias) WithFilterPath(v ...string) func(*IndicesPutAliasReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPutAlias) WithHeader(h map[string]string) func(*IndicesPutAliasRequest) {
+	return func(r *IndicesPutAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPutAlias) WithOpaqueID(s string) func(*IndicesPutAliasRequest) {
+	return func(r *IndicesPutAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.put_index_template.go b/esapi/api.indices.put_index_template.go
new file mode 100644
index 0000000000..4f28026ea8
--- /dev/null
+++ b/esapi/api.indices.put_index_template.go
@@ -0,0 +1,250 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesPutIndexTemplateFunc(t Transport) IndicesPutIndexTemplate {
+	return func(name string, body io.Reader, o ...func(*IndicesPutIndexTemplateRequest)) (*Response, error) {
+		var r = IndicesPutIndexTemplateRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesPutIndexTemplate creates or updates an index template.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesPutIndexTemplate func(name string, body io.Reader, o ...func(*IndicesPutIndexTemplateRequest)) (*Response, error)
+
+// IndicesPutIndexTemplateRequest configures the Indices Put Index Template API request.
+//
+type IndicesPutIndexTemplateRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Cause         string
+	Create        *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesPutIndexTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_index_template") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Cause != "" {
+		params["cause"] = r.Cause
+	}
+
+	if r.Create != nil {
+		params["create"] = strconv.FormatBool(*r.Create)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesPutIndexTemplate) WithContext(v context.Context) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithCause - user defined reason for creating/updating the index template.
+//
+func (f IndicesPutIndexTemplate) WithCause(v string) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.Cause = v
+	}
+}
+
+// WithCreate - whether the index template should only be added if new or can also replace an existing one.
+//
+func (f IndicesPutIndexTemplate) WithCreate(v bool) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.Create = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesPutIndexTemplate) WithMasterTimeout(v time.Duration) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesPutIndexTemplate) WithPretty() func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesPutIndexTemplate) WithHuman() func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesPutIndexTemplate) WithErrorTrace() func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesPutIndexTemplate) WithFilterPath(v ...string) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPutIndexTemplate) WithHeader(h map[string]string) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPutIndexTemplate) WithOpaqueID(s string) func(*IndicesPutIndexTemplateRequest) {
+	return func(r *IndicesPutIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.put_mapping.go b/esapi/api.indices.put_mapping.go
old mode 100755
new mode 100644
index 72745b924f..59f45bacd7
--- a/esapi/api.indices.put_mapping.go
+++ b/esapi/api.indices.put_mapping.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,16 +42,17 @@ func newIndicesPutMappingFunc(t Transport) IndicesPutMapping {
 
 // IndicesPutMapping updates the index mappings.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-put-mapping.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-put-mapping.html.
 //
 type IndicesPutMapping func(body io.Reader, o ...func(*IndicesPutMappingRequest)) (*Response, error)
 
-// IndicesPutMappingRequest configures the Indices  Put Mapping API request.
+// IndicesPutMappingRequest configures the Indices Put Mapping API request.
 //
 type IndicesPutMappingRequest struct {
 	Index        []string
 	DocumentType string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices    *bool
 	ExpandWildcards   string
@@ -41,12 +60,15 @@ type IndicesPutMappingRequest struct {
 	IncludeTypeName   *bool
 	MasterTimeout     time.Duration
 	Timeout           time.Duration
+	WriteIndexOnly    *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -99,6 +121,10 @@ func (r IndicesPutMappingRequest) Do(ctx context.Context, transport Transport) (
 		params["timeout"] = formatDuration(r.Timeout)
 	}
 
+	if r.WriteIndexOnly != nil {
+		params["write_index_only"] = strconv.FormatBool(*r.WriteIndexOnly)
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -115,7 +141,10 @@ func (r IndicesPutMappingRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -129,6 +158,18 @@ func (r IndicesPutMappingRequest) Do(ctx context.Context, transport Transport) (
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -219,6 +260,14 @@ func (f IndicesPutMapping) WithTimeout(v time.Duration) func(*IndicesPutMappingR
 	}
 }
 
+// WithWriteIndexOnly - when true, applies mappings only to the write index of an alias or data stream.
+//
+func (f IndicesPutMapping) WithWriteIndexOnly(v bool) func(*IndicesPutMappingRequest) {
+	return func(r *IndicesPutMappingRequest) {
+		r.WriteIndexOnly = &v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f IndicesPutMapping) WithPretty() func(*IndicesPutMappingRequest) {
@@ -250,3 +299,27 @@ func (f IndicesPutMapping) WithFilterPath(v ...string) func(*IndicesPutMappingRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPutMapping) WithHeader(h map[string]string) func(*IndicesPutMappingRequest) {
+	return func(r *IndicesPutMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPutMapping) WithOpaqueID(s string) func(*IndicesPutMappingRequest) {
+	return func(r *IndicesPutMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.put_settings.go b/esapi/api.indices.put_settings.go
old mode 100755
new mode 100644
index d76769938a..b4a83d2760
--- a/esapi/api.indices.put_settings.go
+++ b/esapi/api.indices.put_settings.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,15 +42,16 @@ func newIndicesPutSettingsFunc(t Transport) IndicesPutSettings {
 
 // IndicesPutSettings updates the index settings.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-update-settings.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-update-settings.html.
 //
 type IndicesPutSettings func(body io.Reader, o ...func(*IndicesPutSettingsRequest)) (*Response, error)
 
-// IndicesPutSettingsRequest configures the Indices  Put Settings API request.
+// IndicesPutSettingsRequest configures the Indices Put Settings API request.
 //
 type IndicesPutSettingsRequest struct {
 	Index []string
-	Body  io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices    *bool
 	ExpandWildcards   string
@@ -47,6 +66,8 @@ type IndicesPutSettingsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -115,7 +136,10 @@ func (r IndicesPutSettingsRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -129,6 +153,18 @@ func (r IndicesPutSettingsRequest) Do(ctx context.Context, transport Transport)
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -250,3 +286,27 @@ func (f IndicesPutSettings) WithFilterPath(v ...string) func(*IndicesPutSettings
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPutSettings) WithHeader(h map[string]string) func(*IndicesPutSettingsRequest) {
+	return func(r *IndicesPutSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPutSettings) WithOpaqueID(s string) func(*IndicesPutSettingsRequest) {
+	return func(r *IndicesPutSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.put_template.go b/esapi/api.indices.put_template.go
old mode 100755
new mode 100644
index ae6b32b023..59c4f076f7
--- a/esapi/api.indices.put_template.go
+++ b/esapi/api.indices.put_template.go
@@ -1,18 +1,36 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
 )
 
 func newIndicesPutTemplateFunc(t Transport) IndicesPutTemplate {
-	return func(body io.Reader, name string, o ...func(*IndicesPutTemplateRequest)) (*Response, error) {
-		var r = IndicesPutTemplateRequest{Body: body, Name: name}
+	return func(name string, body io.Reader, o ...func(*IndicesPutTemplateRequest)) (*Response, error) {
+		var r = IndicesPutTemplateRequest{Name: name, Body: body}
 		for _, f := range o {
 			f(&r)
 		}
@@ -24,28 +42,29 @@ func newIndicesPutTemplateFunc(t Transport) IndicesPutTemplate {
 
 // IndicesPutTemplate creates or updates an index template.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
 //
-type IndicesPutTemplate func(body io.Reader, name string, o ...func(*IndicesPutTemplateRequest)) (*Response, error)
+type IndicesPutTemplate func(name string, body io.Reader, o ...func(*IndicesPutTemplateRequest)) (*Response, error)
 
-// IndicesPutTemplateRequest configures the Indices  Put Template API request.
+// IndicesPutTemplateRequest configures the Indices Put Template API request.
 //
 type IndicesPutTemplateRequest struct {
 	Body io.Reader
 
-	Name            string
+	Name string
+
 	Create          *bool
-	FlatSettings    *bool
 	IncludeTypeName *bool
 	MasterTimeout   time.Duration
 	Order           *int
-	Timeout         time.Duration
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -72,10 +91,6 @@ func (r IndicesPutTemplateRequest) Do(ctx context.Context, transport Transport)
 		params["create"] = strconv.FormatBool(*r.Create)
 	}
 
-	if r.FlatSettings != nil {
-		params["flat_settings"] = strconv.FormatBool(*r.FlatSettings)
-	}
-
 	if r.IncludeTypeName != nil {
 		params["include_type_name"] = strconv.FormatBool(*r.IncludeTypeName)
 	}
@@ -88,10 +103,6 @@ func (r IndicesPutTemplateRequest) Do(ctx context.Context, transport Transport)
 		params["order"] = strconv.FormatInt(int64(*r.Order), 10)
 	}
 
-	if r.Timeout != 0 {
-		params["timeout"] = formatDuration(r.Timeout)
-	}
-
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -108,7 +119,10 @@ func (r IndicesPutTemplateRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -122,6 +136,18 @@ func (r IndicesPutTemplateRequest) Do(ctx context.Context, transport Transport)
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -156,14 +182,6 @@ func (f IndicesPutTemplate) WithCreate(v bool) func(*IndicesPutTemplateRequest)
 	}
 }
 
-// WithFlatSettings - return settings in flat format (default: false).
-//
-func (f IndicesPutTemplate) WithFlatSettings(v bool) func(*IndicesPutTemplateRequest) {
-	return func(r *IndicesPutTemplateRequest) {
-		r.FlatSettings = &v
-	}
-}
-
 // WithIncludeTypeName - whether a type should be returned in the body of the mappings..
 //
 func (f IndicesPutTemplate) WithIncludeTypeName(v bool) func(*IndicesPutTemplateRequest) {
@@ -188,14 +206,6 @@ func (f IndicesPutTemplate) WithOrder(v int) func(*IndicesPutTemplateRequest) {
 	}
 }
 
-// WithTimeout - explicit operation timeout.
-//
-func (f IndicesPutTemplate) WithTimeout(v time.Duration) func(*IndicesPutTemplateRequest) {
-	return func(r *IndicesPutTemplateRequest) {
-		r.Timeout = v
-	}
-}
-
 // WithPretty makes the response body pretty-printed.
 //
 func (f IndicesPutTemplate) WithPretty() func(*IndicesPutTemplateRequest) {
@@ -227,3 +237,27 @@ func (f IndicesPutTemplate) WithFilterPath(v ...string) func(*IndicesPutTemplate
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPutTemplate) WithHeader(h map[string]string) func(*IndicesPutTemplateRequest) {
+	return func(r *IndicesPutTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPutTemplate) WithOpaqueID(s string) func(*IndicesPutTemplateRequest) {
+	return func(r *IndicesPutTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.recovery.go b/esapi/api.indices.recovery.go
old mode 100755
new mode 100644
index f081434a00..b7fade3ab4
--- a/esapi/api.indices.recovery.go
+++ b/esapi/api.indices.recovery.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesRecoveryFunc(t Transport) IndicesRecovery {
 
 // IndicesRecovery returns information about ongoing index shard recoveries.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-recovery.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-recovery.html.
 //
 type IndicesRecovery func(o ...func(*IndicesRecoveryRequest)) (*Response, error)
 
@@ -39,6 +57,8 @@ type IndicesRecoveryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -87,7 +107,10 @@ func (r IndicesRecoveryRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -97,6 +120,18 @@ func (r IndicesRecoveryRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -178,3 +213,27 @@ func (f IndicesRecovery) WithFilterPath(v ...string) func(*IndicesRecoveryReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesRecovery) WithHeader(h map[string]string) func(*IndicesRecoveryRequest) {
+	return func(r *IndicesRecoveryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesRecovery) WithOpaqueID(s string) func(*IndicesRecoveryRequest) {
+	return func(r *IndicesRecoveryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.refresh.go b/esapi/api.indices.refresh.go
old mode 100755
new mode 100644
index 1a8a23cbfd..b40a9a8e82
--- a/esapi/api.indices.refresh.go
+++ b/esapi/api.indices.refresh.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesRefreshFunc(t Transport) IndicesRefresh {
 
 // IndicesRefresh performs the refresh operation in one or more indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html.
 //
 type IndicesRefresh func(o ...func(*IndicesRefreshRequest)) (*Response, error)
 
@@ -40,6 +58,8 @@ type IndicesRefreshRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -92,7 +112,10 @@ func (r IndicesRefreshRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -102,6 +125,18 @@ func (r IndicesRefreshRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,3 +226,27 @@ func (f IndicesRefresh) WithFilterPath(v ...string) func(*IndicesRefreshRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesRefresh) WithHeader(h map[string]string) func(*IndicesRefreshRequest) {
+	return func(r *IndicesRefreshRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesRefresh) WithOpaqueID(s string) func(*IndicesRefreshRequest) {
+	return func(r *IndicesRefreshRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.resolve_index.go b/esapi/api.indices.resolve_index.go
new file mode 100644
index 0000000000..c91f529da3
--- /dev/null
+++ b/esapi/api.indices.resolve_index.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesResolveIndexFunc(t Transport) IndicesResolveIndex {
+	return func(name []string, o ...func(*IndicesResolveIndexRequest)) (*Response, error) {
+		var r = IndicesResolveIndexRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesResolveIndex returns information about any matching indices, aliases, and data streams
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index-api.html.
+//
+type IndicesResolveIndex func(name []string, o ...func(*IndicesResolveIndexRequest)) (*Response, error)
+
+// IndicesResolveIndexRequest configures the Indices Resolve Index API request.
+//
+type IndicesResolveIndexRequest struct {
+	Name []string
+
+	ExpandWildcards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesResolveIndexRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_resolve") + 1 + len("index") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_resolve")
+	path.WriteString("/")
+	path.WriteString("index")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Name, ","))
+
+	params = make(map[string]string)
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesResolveIndex) WithContext(v context.Context) func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.ctx = v
+	}
+}
+
+// WithExpandWildcards - whether wildcard expressions should get expanded to open or closed indices (default: open).
+//
+func (f IndicesResolveIndex) WithExpandWildcards(v string) func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesResolveIndex) WithPretty() func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesResolveIndex) WithHuman() func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesResolveIndex) WithErrorTrace() func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesResolveIndex) WithFilterPath(v ...string) func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesResolveIndex) WithHeader(h map[string]string) func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesResolveIndex) WithOpaqueID(s string) func(*IndicesResolveIndexRequest) {
+	return func(r *IndicesResolveIndexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.rollover.go b/esapi/api.indices.rollover.go
old mode 100755
new mode 100644
index 8dcc67570b..83f91bb5fa
--- a/esapi/api.indices.rollover.go
+++ b/esapi/api.indices.rollover.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -25,7 +43,7 @@ func newIndicesRolloverFunc(t Transport) IndicesRollover {
 // IndicesRollover updates an alias to point to a new index when the existing index
 // is considered to be too large or too old.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-rollover-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-rollover-index.html.
 //
 type IndicesRollover func(alias string, o ...func(*IndicesRolloverRequest)) (*Response, error)
 
@@ -34,8 +52,9 @@ type IndicesRollover func(alias string, o ...func(*IndicesRolloverRequest)) (*Re
 type IndicesRolloverRequest struct {
 	Body io.Reader
 
-	Alias               string
-	NewIndex            string
+	Alias    string
+	NewIndex string
+
 	DryRun              *bool
 	IncludeTypeName     *bool
 	MasterTimeout       time.Duration
@@ -47,6 +66,8 @@ type IndicesRolloverRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -109,7 +130,10 @@ func (r IndicesRolloverRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -123,6 +147,18 @@ func (r IndicesRolloverRequest) Do(ctx context.Context, transport Transport) (*R
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -149,19 +185,19 @@ func (f IndicesRollover) WithContext(v context.Context) func(*IndicesRolloverReq
 	}
 }
 
-// WithNewIndex - the name of the rollover index.
+// WithBody - The conditions that needs to be met for executing rollover.
 //
-func (f IndicesRollover) WithNewIndex(v string) func(*IndicesRolloverRequest) {
+func (f IndicesRollover) WithBody(v io.Reader) func(*IndicesRolloverRequest) {
 	return func(r *IndicesRolloverRequest) {
-		r.NewIndex = v
+		r.Body = v
 	}
 }
 
-// WithBody - The conditions that needs to be met for executing rollover.
+// WithNewIndex - the name of the rollover index.
 //
-func (f IndicesRollover) WithBody(v io.Reader) func(*IndicesRolloverRequest) {
+func (f IndicesRollover) WithNewIndex(v string) func(*IndicesRolloverRequest) {
 	return func(r *IndicesRolloverRequest) {
-		r.Body = v
+		r.NewIndex = v
 	}
 }
 
@@ -236,3 +272,27 @@ func (f IndicesRollover) WithFilterPath(v ...string) func(*IndicesRolloverReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesRollover) WithHeader(h map[string]string) func(*IndicesRolloverRequest) {
+	return func(r *IndicesRolloverRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesRollover) WithOpaqueID(s string) func(*IndicesRolloverRequest) {
+	return func(r *IndicesRolloverRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.segments.go b/esapi/api.indices.segments.go
old mode 100755
new mode 100644
index 5b6478e0bf..40c1e5d079
--- a/esapi/api.indices.segments.go
+++ b/esapi/api.indices.segments.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesSegmentsFunc(t Transport) IndicesSegments {
 
 // IndicesSegments provides low-level information about segments in a Lucene index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-segments.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-segments.html.
 //
 type IndicesSegments func(o ...func(*IndicesSegmentsRequest)) (*Response, error)
 
@@ -41,6 +59,8 @@ type IndicesSegmentsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -97,7 +117,10 @@ func (r IndicesSegmentsRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +130,18 @@ func (r IndicesSegmentsRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -204,3 +239,27 @@ func (f IndicesSegments) WithFilterPath(v ...string) func(*IndicesSegmentsReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesSegments) WithHeader(h map[string]string) func(*IndicesSegmentsRequest) {
+	return func(r *IndicesSegmentsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesSegments) WithOpaqueID(s string) func(*IndicesSegmentsRequest) {
+	return func(r *IndicesSegmentsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.shard_stores.go b/esapi/api.indices.shard_stores.go
old mode 100755
new mode 100644
index 052f23a82f..ce3ed435ef
--- a/esapi/api.indices.shard_stores.go
+++ b/esapi/api.indices.shard_stores.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,11 +40,11 @@ func newIndicesShardStoresFunc(t Transport) IndicesShardStores {
 
 // IndicesShardStores provides store information for shard copies of indices.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-shards-stores.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-shards-stores.html.
 //
 type IndicesShardStores func(o ...func(*IndicesShardStoresRequest)) (*Response, error)
 
-// IndicesShardStoresRequest configures the Indices  Shard Stores API request.
+// IndicesShardStoresRequest configures the Indices Shard Stores API request.
 //
 type IndicesShardStoresRequest struct {
 	Index []string
@@ -41,6 +59,8 @@ type IndicesShardStoresRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -97,7 +117,10 @@ func (r IndicesShardStoresRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +130,18 @@ func (r IndicesShardStoresRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -204,3 +239,27 @@ func (f IndicesShardStores) WithFilterPath(v ...string) func(*IndicesShardStores
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesShardStores) WithHeader(h map[string]string) func(*IndicesShardStoresRequest) {
+	return func(r *IndicesShardStoresRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesShardStores) WithOpaqueID(s string) func(*IndicesShardStoresRequest) {
+	return func(r *IndicesShardStoresRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.shrink.go b/esapi/api.indices.shrink.go
old mode 100755
new mode 100644
index 900417870e..2bdca8effb
--- a/esapi/api.indices.shrink.go
+++ b/esapi/api.indices.shrink.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newIndicesShrinkFunc(t Transport) IndicesShrink {
 
 // IndicesShrink allow to shrink an existing index into a new index with fewer primary shards.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-shrink-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-shrink-index.html.
 //
 type IndicesShrink func(index string, target string, o ...func(*IndicesShrinkRequest)) (*Response, error)
 
@@ -32,9 +50,11 @@ type IndicesShrink func(index string, target string, o ...func(*IndicesShrinkReq
 //
 type IndicesShrinkRequest struct {
 	Index string
-	Body  io.Reader
 
-	Target              string
+	Body io.Reader
+
+	Target string
+
 	CopySettings        *bool
 	MasterTimeout       time.Duration
 	Timeout             time.Duration
@@ -45,6 +65,8 @@ type IndicesShrinkRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -101,7 +123,10 @@ func (r IndicesShrinkRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -115,6 +140,18 @@ func (r IndicesShrinkRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -212,3 +249,27 @@ func (f IndicesShrink) WithFilterPath(v ...string) func(*IndicesShrinkRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesShrink) WithHeader(h map[string]string) func(*IndicesShrinkRequest) {
+	return func(r *IndicesShrinkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesShrink) WithOpaqueID(s string) func(*IndicesShrinkRequest) {
+	return func(r *IndicesShrinkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.simulate_index_template.go b/esapi/api.indices.simulate_index_template.go
new file mode 100644
index 0000000000..0fa98b4e0b
--- /dev/null
+++ b/esapi/api.indices.simulate_index_template.go
@@ -0,0 +1,260 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesSimulateIndexTemplateFunc(t Transport) IndicesSimulateIndexTemplate {
+	return func(name string, o ...func(*IndicesSimulateIndexTemplateRequest)) (*Response, error) {
+		var r = IndicesSimulateIndexTemplateRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesSimulateIndexTemplate simulate matching the given index name against the index templates in the system
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesSimulateIndexTemplate func(name string, o ...func(*IndicesSimulateIndexTemplateRequest)) (*Response, error)
+
+// IndicesSimulateIndexTemplateRequest configures the Indices Simulate Index Template API request.
+//
+type IndicesSimulateIndexTemplateRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Cause         string
+	Create        *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesSimulateIndexTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_index_template") + 1 + len("_simulate_index") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	path.WriteString("/")
+	path.WriteString("_simulate_index")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Cause != "" {
+		params["cause"] = r.Cause
+	}
+
+	if r.Create != nil {
+		params["create"] = strconv.FormatBool(*r.Create)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesSimulateIndexTemplate) WithContext(v context.Context) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - New index template definition, which will be included in the simulation, as if it already exists in the system.
+//
+func (f IndicesSimulateIndexTemplate) WithBody(v io.Reader) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.Body = v
+	}
+}
+
+// WithCause - user defined reason for dry-run creating the new template for simulation purposes.
+//
+func (f IndicesSimulateIndexTemplate) WithCause(v string) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.Cause = v
+	}
+}
+
+// WithCreate - whether the index template we optionally defined in the body should only be dry-run added if new or can also replace an existing one.
+//
+func (f IndicesSimulateIndexTemplate) WithCreate(v bool) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.Create = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesSimulateIndexTemplate) WithMasterTimeout(v time.Duration) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesSimulateIndexTemplate) WithPretty() func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesSimulateIndexTemplate) WithHuman() func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesSimulateIndexTemplate) WithErrorTrace() func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesSimulateIndexTemplate) WithFilterPath(v ...string) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesSimulateIndexTemplate) WithHeader(h map[string]string) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesSimulateIndexTemplate) WithOpaqueID(s string) func(*IndicesSimulateIndexTemplateRequest) {
+	return func(r *IndicesSimulateIndexTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.simulate_template.go b/esapi/api.indices.simulate_template.go
new file mode 100644
index 0000000000..21e6d5ae89
--- /dev/null
+++ b/esapi/api.indices.simulate_template.go
@@ -0,0 +1,270 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesSimulateTemplateFunc(t Transport) IndicesSimulateTemplate {
+	return func(o ...func(*IndicesSimulateTemplateRequest)) (*Response, error) {
+		var r = IndicesSimulateTemplateRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesSimulateTemplate simulate resolving the given template name or body
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-templates.html.
+//
+type IndicesSimulateTemplate func(o ...func(*IndicesSimulateTemplateRequest)) (*Response, error)
+
+// IndicesSimulateTemplateRequest configures the Indices Simulate Template API request.
+//
+type IndicesSimulateTemplateRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Cause         string
+	Create        *bool
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesSimulateTemplateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_index_template") + 1 + len("_simulate") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_index_template")
+	path.WriteString("/")
+	path.WriteString("_simulate")
+	if r.Name != "" {
+		path.WriteString("/")
+		path.WriteString(r.Name)
+	}
+
+	params = make(map[string]string)
+
+	if r.Cause != "" {
+		params["cause"] = r.Cause
+	}
+
+	if r.Create != nil {
+		params["create"] = strconv.FormatBool(*r.Create)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesSimulateTemplate) WithContext(v context.Context) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - New index template definition to be simulated, if no index template name is specified.
+//
+func (f IndicesSimulateTemplate) WithBody(v io.Reader) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Body = v
+	}
+}
+
+// WithName - the name of the index template.
+//
+func (f IndicesSimulateTemplate) WithName(v string) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Name = v
+	}
+}
+
+// WithCause - user defined reason for dry-run creating the new template for simulation purposes.
+//
+func (f IndicesSimulateTemplate) WithCause(v string) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Cause = v
+	}
+}
+
+// WithCreate - whether the index template we optionally defined in the body should only be dry-run added if new or can also replace an existing one.
+//
+func (f IndicesSimulateTemplate) WithCreate(v bool) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Create = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesSimulateTemplate) WithMasterTimeout(v time.Duration) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesSimulateTemplate) WithPretty() func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesSimulateTemplate) WithHuman() func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesSimulateTemplate) WithErrorTrace() func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesSimulateTemplate) WithFilterPath(v ...string) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesSimulateTemplate) WithHeader(h map[string]string) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesSimulateTemplate) WithOpaqueID(s string) func(*IndicesSimulateTemplateRequest) {
+	return func(r *IndicesSimulateTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.split.go b/esapi/api.indices.split.go
old mode 100755
new mode 100644
index 53dd5c8095..f194f80be7
--- a/esapi/api.indices.split.go
+++ b/esapi/api.indices.split.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newIndicesSplitFunc(t Transport) IndicesSplit {
 
 // IndicesSplit allows you to split an existing index into a new index with more primary shards.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-split-index.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-split-index.html.
 //
 type IndicesSplit func(index string, target string, o ...func(*IndicesSplitRequest)) (*Response, error)
 
@@ -32,9 +50,11 @@ type IndicesSplit func(index string, target string, o ...func(*IndicesSplitReque
 //
 type IndicesSplitRequest struct {
 	Index string
-	Body  io.Reader
 
-	Target              string
+	Body io.Reader
+
+	Target string
+
 	CopySettings        *bool
 	MasterTimeout       time.Duration
 	Timeout             time.Duration
@@ -45,6 +65,8 @@ type IndicesSplitRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -101,7 +123,10 @@ func (r IndicesSplitRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -115,6 +140,18 @@ func (r IndicesSplitRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -212,3 +249,27 @@ func (f IndicesSplit) WithFilterPath(v ...string) func(*IndicesSplitRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesSplit) WithHeader(h map[string]string) func(*IndicesSplitRequest) {
+	return func(r *IndicesSplitRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesSplit) WithOpaqueID(s string) func(*IndicesSplitRequest) {
+	return func(r *IndicesSplitRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.stats.go b/esapi/api.indices.stats.go
old mode 100755
new mode 100644
index 813462142f..e67ea98d5a
--- a/esapi/api.indices.stats.go
+++ b/esapi/api.indices.stats.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newIndicesStatsFunc(t Transport) IndicesStats {
 
 // IndicesStats provides statistics on operations happening in an index.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-stats.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-stats.html.
 //
 type IndicesStats func(o ...func(*IndicesStatsRequest)) (*Response, error)
 
@@ -31,12 +49,16 @@ type IndicesStats func(o ...func(*IndicesStatsRequest)) (*Response, error)
 type IndicesStatsRequest struct {
 	Index []string
 
-	Metric                  []string
+	Metric []string
+
 	CompletionFields        []string
+	ExpandWildcards         string
 	FielddataFields         []string
 	Fields                  []string
+	ForbidClosedIndices     *bool
 	Groups                  []string
 	IncludeSegmentFileSizes *bool
+	IncludeUnloadedSegments *bool
 	Level                   string
 	Types                   []string
 
@@ -45,6 +67,8 @@ type IndicesStatsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -77,6 +101,10 @@ func (r IndicesStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["completion_fields"] = strings.Join(r.CompletionFields, ",")
 	}
 
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
 	if len(r.FielddataFields) > 0 {
 		params["fielddata_fields"] = strings.Join(r.FielddataFields, ",")
 	}
@@ -85,6 +113,10 @@ func (r IndicesStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["fields"] = strings.Join(r.Fields, ",")
 	}
 
+	if r.ForbidClosedIndices != nil {
+		params["forbid_closed_indices"] = strconv.FormatBool(*r.ForbidClosedIndices)
+	}
+
 	if len(r.Groups) > 0 {
 		params["groups"] = strings.Join(r.Groups, ",")
 	}
@@ -93,6 +125,10 @@ func (r IndicesStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["include_segment_file_sizes"] = strconv.FormatBool(*r.IncludeSegmentFileSizes)
 	}
 
+	if r.IncludeUnloadedSegments != nil {
+		params["include_unloaded_segments"] = strconv.FormatBool(*r.IncludeUnloadedSegments)
+	}
+
 	if r.Level != "" {
 		params["level"] = r.Level
 	}
@@ -117,7 +153,10 @@ func (r IndicesStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -127,6 +166,18 @@ func (r IndicesStatsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -177,6 +228,14 @@ func (f IndicesStats) WithCompletionFields(v ...string) func(*IndicesStatsReques
 	}
 }
 
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesStats) WithExpandWildcards(v string) func(*IndicesStatsRequest) {
+	return func(r *IndicesStatsRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
 // WithFielddataFields - a list of fields for `fielddata` index metric (supports wildcards).
 //
 func (f IndicesStats) WithFielddataFields(v ...string) func(*IndicesStatsRequest) {
@@ -193,6 +252,14 @@ func (f IndicesStats) WithFields(v ...string) func(*IndicesStatsRequest) {
 	}
 }
 
+// WithForbidClosedIndices - if set to false stats will also collected from closed indices if explicitly specified or if expand_wildcards expands to closed indices.
+//
+func (f IndicesStats) WithForbidClosedIndices(v bool) func(*IndicesStatsRequest) {
+	return func(r *IndicesStatsRequest) {
+		r.ForbidClosedIndices = &v
+	}
+}
+
 // WithGroups - a list of search groups for `search` index metric.
 //
 func (f IndicesStats) WithGroups(v ...string) func(*IndicesStatsRequest) {
@@ -209,6 +276,14 @@ func (f IndicesStats) WithIncludeSegmentFileSizes(v bool) func(*IndicesStatsRequ
 	}
 }
 
+// WithIncludeUnloadedSegments - if set to true segment stats will include stats for segments that are not currently loaded into memory.
+//
+func (f IndicesStats) WithIncludeUnloadedSegments(v bool) func(*IndicesStatsRequest) {
+	return func(r *IndicesStatsRequest) {
+		r.IncludeUnloadedSegments = &v
+	}
+}
+
 // WithLevel - return stats aggregated at cluster, index or shard level.
 //
 func (f IndicesStats) WithLevel(v string) func(*IndicesStatsRequest) {
@@ -256,3 +331,27 @@ func (f IndicesStats) WithFilterPath(v ...string) func(*IndicesStatsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesStats) WithHeader(h map[string]string) func(*IndicesStatsRequest) {
+	return func(r *IndicesStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesStats) WithOpaqueID(s string) func(*IndicesStatsRequest) {
+	return func(r *IndicesStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.update_aliases.go b/esapi/api.indices.update_aliases.go
old mode 100755
new mode 100644
index 37d510cabe..9604b29a01
--- a/esapi/api.indices.update_aliases.go
+++ b/esapi/api.indices.update_aliases.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -23,11 +41,11 @@ func newIndicesUpdateAliasesFunc(t Transport) IndicesUpdateAliases {
 
 // IndicesUpdateAliases updates index aliases.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-aliases.html.
 //
 type IndicesUpdateAliases func(body io.Reader, o ...func(*IndicesUpdateAliasesRequest)) (*Response, error)
 
-// IndicesUpdateAliasesRequest configures the Indices  Update Aliases API request.
+// IndicesUpdateAliasesRequest configures the Indices Update Aliases API request.
 //
 type IndicesUpdateAliasesRequest struct {
 	Body io.Reader
@@ -40,6 +58,8 @@ type IndicesUpdateAliasesRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -83,7 +103,10 @@ func (r IndicesUpdateAliasesRequest) Do(ctx context.Context, transport Transport
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -97,6 +120,18 @@ func (r IndicesUpdateAliasesRequest) Do(ctx context.Context, transport Transport
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -170,3 +205,27 @@ func (f IndicesUpdateAliases) WithFilterPath(v ...string) func(*IndicesUpdateAli
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesUpdateAliases) WithHeader(h map[string]string) func(*IndicesUpdateAliasesRequest) {
+	return func(r *IndicesUpdateAliasesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesUpdateAliases) WithOpaqueID(s string) func(*IndicesUpdateAliasesRequest) {
+	return func(r *IndicesUpdateAliasesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.upgrade.go b/esapi/api.indices.upgrade.go
old mode 100755
new mode 100644
index e6da5915c8..0ee730b4c2
--- a/esapi/api.indices.upgrade.go
+++ b/esapi/api.indices.upgrade.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -20,9 +38,9 @@ func newIndicesUpgradeFunc(t Transport) IndicesUpgrade {
 
 // ----- API Definition -------------------------------------------------------
 
-// IndicesUpgrade the _upgrade API is no longer useful and will be removed.
+// IndicesUpgrade deprecated Upgrades to the current version of Lucene.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-upgrade.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-upgrade.html.
 //
 type IndicesUpgrade func(o ...func(*IndicesUpgradeRequest)) (*Response, error)
 
@@ -42,6 +60,8 @@ type IndicesUpgradeRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -102,7 +122,10 @@ func (r IndicesUpgradeRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -112,6 +135,18 @@ func (r IndicesUpgradeRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -217,3 +252,27 @@ func (f IndicesUpgrade) WithFilterPath(v ...string) func(*IndicesUpgradeRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesUpgrade) WithHeader(h map[string]string) func(*IndicesUpgradeRequest) {
+	return func(r *IndicesUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesUpgrade) WithOpaqueID(s string) func(*IndicesUpgradeRequest) {
+	return func(r *IndicesUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.indices.validate_query.go b/esapi/api.indices.validate_query.go
old mode 100755
new mode 100644
index c2eef0199e..a0d141551e
--- a/esapi/api.indices.validate_query.go
+++ b/esapi/api.indices.validate_query.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,16 +41,17 @@ func newIndicesValidateQueryFunc(t Transport) IndicesValidateQuery {
 
 // IndicesValidateQuery allows a user to validate a potentially expensive query without executing it.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-validate.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-validate.html.
 //
 type IndicesValidateQuery func(o ...func(*IndicesValidateQueryRequest)) (*Response, error)
 
-// IndicesValidateQueryRequest configures the Indices  Validate Query API request.
+// IndicesValidateQueryRequest configures the Indices Validate Query API request.
 //
 type IndicesValidateQueryRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices    *bool
 	AllShards         *bool
@@ -52,6 +71,8 @@ type IndicesValidateQueryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -64,7 +85,7 @@ func (r IndicesValidateQueryRequest) Do(ctx context.Context, transport Transport
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_validate") + 1 + len("query"))
 	if len(r.Index) > 0 {
@@ -146,7 +167,10 @@ func (r IndicesValidateQueryRequest) Do(ctx context.Context, transport Transport
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -160,6 +184,18 @@ func (r IndicesValidateQueryRequest) Do(ctx context.Context, transport Transport
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -186,6 +222,14 @@ func (f IndicesValidateQuery) WithContext(v context.Context) func(*IndicesValida
 	}
 }
 
+// WithBody - The query definition specified with the Query DSL.
+//
+func (f IndicesValidateQuery) WithBody(v io.Reader) func(*IndicesValidateQueryRequest) {
+	return func(r *IndicesValidateQueryRequest) {
+		r.Body = v
+	}
+}
+
 // WithIndex - a list of index names to restrict the operation; use _all to perform the operation on all indices.
 //
 func (f IndicesValidateQuery) WithIndex(v ...string) func(*IndicesValidateQueryRequest) {
@@ -202,14 +246,6 @@ func (f IndicesValidateQuery) WithDocumentType(v ...string) func(*IndicesValidat
 	}
 }
 
-// WithBody - The query definition specified with the Query DSL.
-//
-func (f IndicesValidateQuery) WithBody(v io.Reader) func(*IndicesValidateQueryRequest) {
-	return func(r *IndicesValidateQueryRequest) {
-		r.Body = v
-	}
-}
-
 // WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
 //
 func (f IndicesValidateQuery) WithAllowNoIndices(v bool) func(*IndicesValidateQueryRequest) {
@@ -337,3 +373,27 @@ func (f IndicesValidateQuery) WithFilterPath(v ...string) func(*IndicesValidateQ
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesValidateQuery) WithHeader(h map[string]string) func(*IndicesValidateQueryRequest) {
+	return func(r *IndicesValidateQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesValidateQuery) WithOpaqueID(s string) func(*IndicesValidateQueryRequest) {
+	return func(r *IndicesValidateQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.info.go b/esapi/api.info.go
old mode 100755
new mode 100644
index 11fb6464d4..687d4c8f29
--- a/esapi/api.info.go
+++ b/esapi/api.info.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 )
 
@@ -21,7 +39,7 @@ func newInfoFunc(t Transport) Info {
 
 // Info returns basic information about the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html.
 //
 type Info func(o ...func(*InfoRequest)) (*Response, error)
 
@@ -33,6 +51,8 @@ type InfoRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -68,7 +88,10 @@ func (r InfoRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -78,6 +101,18 @@ func (r InfoRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -127,3 +162,27 @@ func (f Info) WithFilterPath(v ...string) func(*InfoRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Info) WithHeader(h map[string]string) func(*InfoRequest) {
+	return func(r *InfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Info) WithOpaqueID(s string) func(*InfoRequest) {
+	return func(r *InfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.delete_pipeline.go b/esapi/api.ingest.delete_pipeline.go
old mode 100755
new mode 100644
index b541b70ca4..09d716790d
--- a/esapi/api.ingest.delete_pipeline.go
+++ b/esapi/api.ingest.delete_pipeline.go
@@ -1,16 +1,34 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
 
 func newIngestDeletePipelineFunc(t Transport) IngestDeletePipeline {
 	return func(id string, o ...func(*IngestDeletePipelineRequest)) (*Response, error) {
-		var r = IngestDeletePipelineRequest{DocumentID: id}
+		var r = IngestDeletePipelineRequest{PipelineID: id}
 		for _, f := range o {
 			f(&r)
 		}
@@ -22,14 +40,14 @@ func newIngestDeletePipelineFunc(t Transport) IngestDeletePipeline {
 
 // IngestDeletePipeline deletes a pipeline.
 //
-// See full documentation at https://www.elastic.co/guide/en/elasticsearch/plugins/master/ingest.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-pipeline-api.html.
 //
 type IngestDeletePipeline func(id string, o ...func(*IngestDeletePipelineRequest)) (*Response, error)
 
-// IngestDeletePipelineRequest configures the Ingest  Delete Pipeline API request.
+// IngestDeletePipelineRequest configures the Ingest Delete Pipeline API request.
 //
 type IngestDeletePipelineRequest struct {
-	DocumentID string
+	PipelineID string
 
 	MasterTimeout time.Duration
 	Timeout       time.Duration
@@ -39,6 +57,8 @@ type IngestDeletePipelineRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -53,13 +73,13 @@ func (r IngestDeletePipelineRequest) Do(ctx context.Context, transport Transport
 
 	method = "DELETE"
 
-	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.PipelineID))
 	path.WriteString("/")
 	path.WriteString("_ingest")
 	path.WriteString("/")
 	path.WriteString("pipeline")
 	path.WriteString("/")
-	path.WriteString(r.DocumentID)
+	path.WriteString(r.PipelineID)
 
 	params = make(map[string]string)
 
@@ -87,7 +107,10 @@ func (r IngestDeletePipelineRequest) Do(ctx context.Context, transport Transport
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -97,6 +120,18 @@ func (r IngestDeletePipelineRequest) Do(ctx context.Context, transport Transport
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -170,3 +205,27 @@ func (f IngestDeletePipeline) WithFilterPath(v ...string) func(*IngestDeletePipe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestDeletePipeline) WithHeader(h map[string]string) func(*IngestDeletePipelineRequest) {
+	return func(r *IngestDeletePipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestDeletePipeline) WithOpaqueID(s string) func(*IngestDeletePipelineRequest) {
+	return func(r *IngestDeletePipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.geo_ip_stats.go b/esapi/api.ingest.geo_ip_stats.go
new file mode 100644
index 0000000000..afc3bde4e9
--- /dev/null
+++ b/esapi/api.ingest.geo_ip_stats.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIngestGeoIPStatsFunc(t Transport) IngestGeoIPStats {
+	return func(o ...func(*IngestGeoIPStatsRequest)) (*Response, error) {
+		var r = IngestGeoIPStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IngestGeoIPStats returns statistical information about geoip databases
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/geoip-stats-api.html.
+//
+type IngestGeoIPStats func(o ...func(*IngestGeoIPStatsRequest)) (*Response, error)
+
+// IngestGeoIPStatsRequest configures the Ingest GeoIP Stats API request.
+//
+type IngestGeoIPStatsRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IngestGeoIPStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_ingest/geoip/stats"))
+	path.WriteString("/_ingest/geoip/stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IngestGeoIPStats) WithContext(v context.Context) func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IngestGeoIPStats) WithPretty() func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IngestGeoIPStats) WithHuman() func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IngestGeoIPStats) WithErrorTrace() func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IngestGeoIPStats) WithFilterPath(v ...string) func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestGeoIPStats) WithHeader(h map[string]string) func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestGeoIPStats) WithOpaqueID(s string) func(*IngestGeoIPStatsRequest) {
+	return func(r *IngestGeoIPStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.get_pipeline.go b/esapi/api.ingest.get_pipeline.go
old mode 100755
new mode 100644
index 5874869256..c718b0783c
--- a/esapi/api.ingest.get_pipeline.go
+++ b/esapi/api.ingest.get_pipeline.go
@@ -1,9 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -22,22 +41,25 @@ func newIngestGetPipelineFunc(t Transport) IngestGetPipeline {
 
 // IngestGetPipeline returns a pipeline.
 //
-// See full documentation at https://www.elastic.co/guide/en/elasticsearch/plugins/master/ingest.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-pipeline-api.html.
 //
 type IngestGetPipeline func(o ...func(*IngestGetPipelineRequest)) (*Response, error)
 
-// IngestGetPipelineRequest configures the Ingest  Get Pipeline API request.
+// IngestGetPipelineRequest configures the Ingest Get Pipeline API request.
 //
 type IngestGetPipelineRequest struct {
-	DocumentID string
+	PipelineID string
 
 	MasterTimeout time.Duration
+	Summary       *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -52,14 +74,14 @@ func (r IngestGetPipelineRequest) Do(ctx context.Context, transport Transport) (
 
 	method = "GET"
 
-	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.PipelineID))
 	path.WriteString("/")
 	path.WriteString("_ingest")
 	path.WriteString("/")
 	path.WriteString("pipeline")
-	if r.DocumentID != "" {
+	if r.PipelineID != "" {
 		path.WriteString("/")
-		path.WriteString(r.DocumentID)
+		path.WriteString(r.PipelineID)
 	}
 
 	params = make(map[string]string)
@@ -68,6 +90,10 @@ func (r IngestGetPipelineRequest) Do(ctx context.Context, transport Transport) (
 		params["master_timeout"] = formatDuration(r.MasterTimeout)
 	}
 
+	if r.Summary != nil {
+		params["summary"] = strconv.FormatBool(*r.Summary)
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -84,7 +110,10 @@ func (r IngestGetPipelineRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -94,6 +123,18 @@ func (r IngestGetPipelineRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -120,11 +161,11 @@ func (f IngestGetPipeline) WithContext(v context.Context) func(*IngestGetPipelin
 	}
 }
 
-// WithDocumentID - comma separated list of pipeline ids. wildcards supported.
+// WithPipelineID - comma separated list of pipeline ids. wildcards supported.
 //
-func (f IngestGetPipeline) WithDocumentID(v string) func(*IngestGetPipelineRequest) {
+func (f IngestGetPipeline) WithPipelineID(v string) func(*IngestGetPipelineRequest) {
 	return func(r *IngestGetPipelineRequest) {
-		r.DocumentID = v
+		r.PipelineID = v
 	}
 }
 
@@ -136,6 +177,14 @@ func (f IngestGetPipeline) WithMasterTimeout(v time.Duration) func(*IngestGetPip
 	}
 }
 
+// WithSummary - return pipelines without their definitions (default: false).
+//
+func (f IngestGetPipeline) WithSummary(v bool) func(*IngestGetPipelineRequest) {
+	return func(r *IngestGetPipelineRequest) {
+		r.Summary = &v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f IngestGetPipeline) WithPretty() func(*IngestGetPipelineRequest) {
@@ -167,3 +216,27 @@ func (f IngestGetPipeline) WithFilterPath(v ...string) func(*IngestGetPipelineRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestGetPipeline) WithHeader(h map[string]string) func(*IngestGetPipelineRequest) {
+	return func(r *IngestGetPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestGetPipeline) WithOpaqueID(s string) func(*IngestGetPipelineRequest) {
+	return func(r *IngestGetPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.processor_grok.go b/esapi/api.ingest.processor_grok.go
old mode 100755
new mode 100644
index 697c7b8245..5c9561a01d
--- a/esapi/api.ingest.processor_grok.go
+++ b/esapi/api.ingest.processor_grok.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 )
 
@@ -21,11 +39,11 @@ func newIngestProcessorGrokFunc(t Transport) IngestProcessorGrok {
 
 // IngestProcessorGrok returns a list of the built-in patterns.
 //
-// See full documentation at https://www.elastic.co/guide/en/elasticsearch/plugins/master/ingest.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/grok-processor.html#grok-processor-rest-get.
 //
 type IngestProcessorGrok func(o ...func(*IngestProcessorGrokRequest)) (*Response, error)
 
-// IngestProcessorGrokRequest configures the Ingest  Processor Grok API request.
+// IngestProcessorGrokRequest configures the Ingest Processor Grok API request.
 //
 type IngestProcessorGrokRequest struct {
 	Pretty     bool
@@ -33,6 +51,8 @@ type IngestProcessorGrokRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -68,7 +88,10 @@ func (r IngestProcessorGrokRequest) Do(ctx context.Context, transport Transport)
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -78,6 +101,18 @@ func (r IngestProcessorGrokRequest) Do(ctx context.Context, transport Transport)
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -135,3 +170,27 @@ func (f IngestProcessorGrok) WithFilterPath(v ...string) func(*IngestProcessorGr
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestProcessorGrok) WithHeader(h map[string]string) func(*IngestProcessorGrokRequest) {
+	return func(r *IngestProcessorGrokRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestProcessorGrok) WithOpaqueID(s string) func(*IngestProcessorGrokRequest) {
+	return func(r *IngestProcessorGrokRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.put_pipeline.go b/esapi/api.ingest.put_pipeline.go
old mode 100755
new mode 100644
index 87ac91236e..695d816df6
--- a/esapi/api.ingest.put_pipeline.go
+++ b/esapi/api.ingest.put_pipeline.go
@@ -1,17 +1,36 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
+	"strconv"
 	"strings"
 	"time"
 )
 
 func newIngestPutPipelineFunc(t Transport) IngestPutPipeline {
 	return func(id string, body io.Reader, o ...func(*IngestPutPipelineRequest)) (*Response, error) {
-		var r = IngestPutPipelineRequest{DocumentID: id, Body: body}
+		var r = IngestPutPipelineRequest{PipelineID: id, Body: body}
 		for _, f := range o {
 			f(&r)
 		}
@@ -23,16 +42,18 @@ func newIngestPutPipelineFunc(t Transport) IngestPutPipeline {
 
 // IngestPutPipeline creates or updates a pipeline.
 //
-// See full documentation at https://www.elastic.co/guide/en/elasticsearch/plugins/master/ingest.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/put-pipeline-api.html.
 //
 type IngestPutPipeline func(id string, body io.Reader, o ...func(*IngestPutPipelineRequest)) (*Response, error)
 
-// IngestPutPipelineRequest configures the Ingest  Put Pipeline API request.
+// IngestPutPipelineRequest configures the Ingest Put Pipeline API request.
 //
 type IngestPutPipelineRequest struct {
-	DocumentID string
-	Body       io.Reader
+	PipelineID string
+
+	Body io.Reader
 
+	IfVersion     *int
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -41,6 +62,8 @@ type IngestPutPipelineRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -55,16 +78,20 @@ func (r IngestPutPipelineRequest) Do(ctx context.Context, transport Transport) (
 
 	method = "PUT"
 
-	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.PipelineID))
 	path.WriteString("/")
 	path.WriteString("_ingest")
 	path.WriteString("/")
 	path.WriteString("pipeline")
 	path.WriteString("/")
-	path.WriteString(r.DocumentID)
+	path.WriteString(r.PipelineID)
 
 	params = make(map[string]string)
 
+	if r.IfVersion != nil {
+		params["if_version"] = strconv.FormatInt(int64(*r.IfVersion), 10)
+	}
+
 	if r.MasterTimeout != 0 {
 		params["master_timeout"] = formatDuration(r.MasterTimeout)
 	}
@@ -89,7 +116,10 @@ func (r IngestPutPipelineRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -103,6 +133,18 @@ func (r IngestPutPipelineRequest) Do(ctx context.Context, transport Transport) (
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -129,6 +171,14 @@ func (f IngestPutPipeline) WithContext(v context.Context) func(*IngestPutPipelin
 	}
 }
 
+// WithIfVersion - required version for optimistic concurrency control for pipeline updates.
+//
+func (f IngestPutPipeline) WithIfVersion(v int) func(*IngestPutPipelineRequest) {
+	return func(r *IngestPutPipelineRequest) {
+		r.IfVersion = &v
+	}
+}
+
 // WithMasterTimeout - explicit operation timeout for connection to master node.
 //
 func (f IngestPutPipeline) WithMasterTimeout(v time.Duration) func(*IngestPutPipelineRequest) {
@@ -176,3 +226,27 @@ func (f IngestPutPipeline) WithFilterPath(v ...string) func(*IngestPutPipelineRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestPutPipeline) WithHeader(h map[string]string) func(*IngestPutPipelineRequest) {
+	return func(r *IngestPutPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestPutPipeline) WithOpaqueID(s string) func(*IngestPutPipelineRequest) {
+	return func(r *IngestPutPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ingest.simulate.go b/esapi/api.ingest.simulate.go
old mode 100755
new mode 100644
index b2070b5e83..36fd759d0f
--- a/esapi/api.ingest.simulate.go
+++ b/esapi/api.ingest.simulate.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,15 +41,16 @@ func newIngestSimulateFunc(t Transport) IngestSimulate {
 
 // IngestSimulate allows to simulate a pipeline with example documents.
 //
-// See full documentation at https://www.elastic.co/guide/en/elasticsearch/plugins/master/ingest.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/simulate-pipeline-api.html.
 //
 type IngestSimulate func(body io.Reader, o ...func(*IngestSimulateRequest)) (*Response, error)
 
 // IngestSimulateRequest configures the Ingest Simulate API request.
 //
 type IngestSimulateRequest struct {
-	DocumentID string
-	Body       io.Reader
+	PipelineID string
+
+	Body io.Reader
 
 	Verbose *bool
 
@@ -40,6 +59,8 @@ type IngestSimulateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -52,16 +73,16 @@ func (r IngestSimulateRequest) Do(ctx context.Context, transport Transport) (*Re
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
-	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.DocumentID) + 1 + len("_simulate"))
+	path.Grow(1 + len("_ingest") + 1 + len("pipeline") + 1 + len(r.PipelineID) + 1 + len("_simulate"))
 	path.WriteString("/")
 	path.WriteString("_ingest")
 	path.WriteString("/")
 	path.WriteString("pipeline")
-	if r.DocumentID != "" {
+	if r.PipelineID != "" {
 		path.WriteString("/")
-		path.WriteString(r.DocumentID)
+		path.WriteString(r.PipelineID)
 	}
 	path.WriteString("/")
 	path.WriteString("_simulate")
@@ -88,7 +109,10 @@ func (r IngestSimulateRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -102,6 +126,18 @@ func (r IngestSimulateRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -128,11 +164,11 @@ func (f IngestSimulate) WithContext(v context.Context) func(*IngestSimulateReque
 	}
 }
 
-// WithDocumentID - pipeline ID.
+// WithPipelineID - pipeline ID.
 //
-func (f IngestSimulate) WithDocumentID(v string) func(*IngestSimulateRequest) {
+func (f IngestSimulate) WithPipelineID(v string) func(*IngestSimulateRequest) {
 	return func(r *IngestSimulateRequest) {
-		r.DocumentID = v
+		r.PipelineID = v
 	}
 }
 
@@ -175,3 +211,27 @@ func (f IngestSimulate) WithFilterPath(v ...string) func(*IngestSimulateRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IngestSimulate) WithHeader(h map[string]string) func(*IngestSimulateRequest) {
+	return func(r *IngestSimulateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IngestSimulate) WithOpaqueID(s string) func(*IngestSimulateRequest) {
+	return func(r *IngestSimulateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.mget.go b/esapi/api.mget.go
old mode 100755
new mode 100644
index c51f4632c7..9497ad29fe
--- a/esapi/api.mget.go
+++ b/esapi/api.mget.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newMgetFunc(t Transport) Mget {
 
 // Mget allows to get multiple documents in one request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-multi-get.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-multi-get.html.
 //
 type Mget func(body io.Reader, o ...func(*MgetRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type Mget func(body io.Reader, o ...func(*MgetRequest)) (*Response, error)
 type MgetRequest struct {
 	Index        string
 	DocumentType string
-	Body         io.Reader
+
+	Body io.Reader
 
 	Preference     string
 	Realtime       *bool
@@ -48,6 +67,8 @@ type MgetRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -60,7 +81,7 @@ func (r MgetRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(r.Index) + 1 + len(r.DocumentType) + 1 + len("_mget"))
 	if r.Index != "" {
@@ -124,7 +145,10 @@ func (r MgetRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -138,6 +162,18 @@ func (r MgetRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -275,3 +311,27 @@ func (f Mget) WithFilterPath(v ...string) func(*MgetRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Mget) WithHeader(h map[string]string) func(*MgetRequest) {
+	return func(r *MgetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Mget) WithOpaqueID(s string) func(*MgetRequest) {
+	return func(r *MgetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.msearch.go b/esapi/api.msearch.go
old mode 100755
new mode 100644
index 3858f168b6..58487430c4
--- a/esapi/api.msearch.go
+++ b/esapi/api.msearch.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newMsearchFunc(t Transport) Msearch {
 
 // Msearch allows to execute several search operations in one request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-multi-search.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-multi-search.html.
 //
 type Msearch func(body io.Reader, o ...func(*MsearchRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type Msearch func(body io.Reader, o ...func(*MsearchRequest)) (*Response, error)
 type MsearchRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	CcsMinimizeRoundtrips      *bool
 	MaxConcurrentSearches      *int
@@ -47,6 +66,8 @@ type MsearchRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -59,7 +80,7 @@ func (r MsearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_msearch"))
 	if len(r.Index) > 0 {
@@ -119,7 +140,10 @@ func (r MsearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -133,6 +157,18 @@ func (r MsearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,7 +227,7 @@ func (f Msearch) WithMaxConcurrentSearches(v int) func(*MsearchRequest) {
 	}
 }
 
-// WithMaxConcurrentShardRequests - the number of concurrent shard requests each sub search executes concurrently. this value should be used to limit the impact of the search on the cluster in order to limit the number of concurrent shard requests.
+// WithMaxConcurrentShardRequests - the number of concurrent shard requests each sub search executes concurrently per node. this value should be used to limit the impact of the search on the cluster in order to limit the number of concurrent shard requests.
 //
 func (f Msearch) WithMaxConcurrentShardRequests(v int) func(*MsearchRequest) {
 	return func(r *MsearchRequest) {
@@ -199,7 +235,7 @@ func (f Msearch) WithMaxConcurrentShardRequests(v int) func(*MsearchRequest) {
 	}
 }
 
-// WithPreFilterShardSize - a threshold that enforces a pre-filter roundtrip to prefilter search shards based on query rewriting if the number of shards the search request expands to exceeds the threshold. this filter roundtrip can limit the number of shards significantly if for instance a shard can not match any documents based on it's rewrite method ie. if date filters are mandatory to match but the shard bounds and the query are disjoint..
+// WithPreFilterShardSize - a threshold that enforces a pre-filter roundtrip to prefilter search shards based on query rewriting if the number of shards the search request expands to exceeds the threshold. this filter roundtrip can limit the number of shards significantly if for instance a shard can not match any documents based on its rewrite method ie. if date filters are mandatory to match but the shard bounds and the query are disjoint..
 //
 func (f Msearch) WithPreFilterShardSize(v int) func(*MsearchRequest) {
 	return func(r *MsearchRequest) {
@@ -262,3 +298,27 @@ func (f Msearch) WithFilterPath(v ...string) func(*MsearchRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Msearch) WithHeader(h map[string]string) func(*MsearchRequest) {
+	return func(r *MsearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Msearch) WithOpaqueID(s string) func(*MsearchRequest) {
+	return func(r *MsearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.msearch_template.go b/esapi/api.msearch_template.go
old mode 100755
new mode 100644
index 7ed2c96c54..e089972172
--- a/esapi/api.msearch_template.go
+++ b/esapi/api.msearch_template.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newMsearchTemplateFunc(t Transport) MsearchTemplate {
 
 // MsearchTemplate allows to execute several search template operations in one request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html.
 //
 type MsearchTemplate func(body io.Reader, o ...func(*MsearchTemplateRequest)) (*Response, error)
 
@@ -32,7 +50,8 @@ type MsearchTemplate func(body io.Reader, o ...func(*MsearchTemplateRequest)) (*
 type MsearchTemplateRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	CcsMinimizeRoundtrips *bool
 	MaxConcurrentSearches *int
@@ -45,6 +64,8 @@ type MsearchTemplateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -57,7 +78,7 @@ func (r MsearchTemplateRequest) Do(ctx context.Context, transport Transport) (*R
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_msearch") + 1 + len("template"))
 	if len(r.Index) > 0 {
@@ -111,7 +132,10 @@ func (r MsearchTemplateRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -125,6 +149,18 @@ func (r MsearchTemplateRequest) Do(ctx context.Context, transport Transport) (*R
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -238,3 +274,27 @@ func (f MsearchTemplate) WithFilterPath(v ...string) func(*MsearchTemplateReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MsearchTemplate) WithHeader(h map[string]string) func(*MsearchTemplateRequest) {
+	return func(r *MsearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MsearchTemplate) WithOpaqueID(s string) func(*MsearchTemplateRequest) {
+	return func(r *MsearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.mtermvectors.go b/esapi/api.mtermvectors.go
old mode 100755
new mode 100644
index 924744d8fa..4a77341b28
--- a/esapi/api.mtermvectors.go
+++ b/esapi/api.mtermvectors.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newMtermvectorsFunc(t Transport) Mtermvectors {
 
 // Mtermvectors returns multiple termvectors in one request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-multi-termvectors.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-multi-termvectors.html.
 //
 type Mtermvectors func(o ...func(*MtermvectorsRequest)) (*Response, error)
 
@@ -32,13 +50,13 @@ type Mtermvectors func(o ...func(*MtermvectorsRequest)) (*Response, error)
 type MtermvectorsRequest struct {
 	Index        string
 	DocumentType string
-	Body         io.Reader
+
+	Body io.Reader
 
 	Fields          []string
 	FieldStatistics *bool
 	Ids             []string
 	Offsets         *bool
-	Parent          string
 	Payloads        *bool
 	Positions       *bool
 	Preference      string
@@ -53,6 +71,8 @@ type MtermvectorsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -65,7 +85,7 @@ func (r MtermvectorsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(r.Index) + 1 + len(r.DocumentType) + 1 + len("_mtermvectors"))
 	if r.Index != "" {
@@ -97,10 +117,6 @@ func (r MtermvectorsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["offsets"] = strconv.FormatBool(*r.Offsets)
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Payloads != nil {
 		params["payloads"] = strconv.FormatBool(*r.Payloads)
 	}
@@ -149,7 +165,10 @@ func (r MtermvectorsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -163,6 +182,18 @@ func (r MtermvectorsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -189,6 +220,14 @@ func (f Mtermvectors) WithContext(v context.Context) func(*MtermvectorsRequest)
 	}
 }
 
+// WithBody - Define ids, documents, parameters or a list of parameters per document here. You must at least provide a list of document ids. See documentation..
+//
+func (f Mtermvectors) WithBody(v io.Reader) func(*MtermvectorsRequest) {
+	return func(r *MtermvectorsRequest) {
+		r.Body = v
+	}
+}
+
 // WithIndex - the index in which the document resides..
 //
 func (f Mtermvectors) WithIndex(v string) func(*MtermvectorsRequest) {
@@ -205,14 +244,6 @@ func (f Mtermvectors) WithDocumentType(v string) func(*MtermvectorsRequest) {
 	}
 }
 
-// WithBody - Define ids, documents, parameters or a list of parameters per document here. You must at least provide a list of document ids. See documentation..
-//
-func (f Mtermvectors) WithBody(v io.Reader) func(*MtermvectorsRequest) {
-	return func(r *MtermvectorsRequest) {
-		r.Body = v
-	}
-}
-
 // WithFields - a list of fields to return. applies to all returned documents unless otherwise specified in body "params" or "docs"..
 //
 func (f Mtermvectors) WithFields(v ...string) func(*MtermvectorsRequest) {
@@ -245,14 +276,6 @@ func (f Mtermvectors) WithOffsets(v bool) func(*MtermvectorsRequest) {
 	}
 }
 
-// WithParent - parent ID of documents. applies to all returned documents unless otherwise specified in body "params" or "docs"..
-//
-func (f Mtermvectors) WithParent(v string) func(*MtermvectorsRequest) {
-	return func(r *MtermvectorsRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPayloads - specifies if term payloads should be returned. applies to all returned documents unless otherwise specified in body "params" or "docs"..
 //
 func (f Mtermvectors) WithPayloads(v bool) func(*MtermvectorsRequest) {
@@ -348,3 +371,27 @@ func (f Mtermvectors) WithFilterPath(v ...string) func(*MtermvectorsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Mtermvectors) WithHeader(h map[string]string) func(*MtermvectorsRequest) {
+	return func(r *MtermvectorsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Mtermvectors) WithOpaqueID(s string) func(*MtermvectorsRequest) {
+	return func(r *MtermvectorsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.clear_metering_archive.go b/esapi/api.nodes.clear_metering_archive.go
new file mode 100644
index 0000000000..9208e183c8
--- /dev/null
+++ b/esapi/api.nodes.clear_metering_archive.go
@@ -0,0 +1,209 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.x: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newNodesClearMeteringArchiveFunc(t Transport) NodesClearMeteringArchive {
+	return func(max_archive_version *int, node_id []string, o ...func(*NodesClearMeteringArchiveRequest)) (*Response, error) {
+		var r = NodesClearMeteringArchiveRequest{NodeID: node_id, MaxArchiveVersion: max_archive_version}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// NodesClearMeteringArchive removes the archived repositories metering information present in the cluster.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/clear-repositories-metering-archive-api.html.
+//
+type NodesClearMeteringArchive func(max_archive_version *int, node_id []string, o ...func(*NodesClearMeteringArchiveRequest)) (*Response, error)
+
+// NodesClearMeteringArchiveRequest configures the Nodes Clear Metering Archive API request.
+//
+type NodesClearMeteringArchiveRequest struct {
+	MaxArchiveVersion *int
+	NodeID            []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r NodesClearMeteringArchiveRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_nodes") + 1 + len(strings.Join(r.NodeID, ",")) + 1 + len("_repositories_metering") + 1 + len(strconv.Itoa(*r.MaxArchiveVersion)))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.NodeID, ","))
+	path.WriteString("/")
+	path.WriteString("_repositories_metering")
+	path.WriteString("/")
+	path.WriteString(strconv.Itoa(*r.MaxArchiveVersion))
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f NodesClearMeteringArchive) WithContext(v context.Context) func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f NodesClearMeteringArchive) WithPretty() func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f NodesClearMeteringArchive) WithHuman() func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f NodesClearMeteringArchive) WithErrorTrace() func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f NodesClearMeteringArchive) WithFilterPath(v ...string) func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesClearMeteringArchive) WithHeader(h map[string]string) func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesClearMeteringArchive) WithOpaqueID(s string) func(*NodesClearMeteringArchiveRequest) {
+	return func(r *NodesClearMeteringArchiveRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.clear_repositories_metering_archive.go b/esapi/api.nodes.clear_repositories_metering_archive.go
new file mode 100644
index 0000000000..34fd788d92
--- /dev/null
+++ b/esapi/api.nodes.clear_repositories_metering_archive.go
@@ -0,0 +1,209 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newNodesClearRepositoriesMeteringArchiveFunc(t Transport) NodesClearRepositoriesMeteringArchive {
+	return func(node_id []string, max_archive_version *int, o ...func(*NodesClearRepositoriesMeteringArchiveRequest)) (*Response, error) {
+		var r = NodesClearRepositoriesMeteringArchiveRequest{NodeID: node_id, MaxArchiveVersion: max_archive_version}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// NodesClearRepositoriesMeteringArchive removes the archived repositories metering information present in the cluster.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/clear-repositories-metering-archive-api.html.
+//
+type NodesClearRepositoriesMeteringArchive func(node_id []string, max_archive_version *int, o ...func(*NodesClearRepositoriesMeteringArchiveRequest)) (*Response, error)
+
+// NodesClearRepositoriesMeteringArchiveRequest configures the Nodes Clear Repositories Metering Archive API request.
+//
+type NodesClearRepositoriesMeteringArchiveRequest struct {
+	MaxArchiveVersion *int
+	NodeID            []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r NodesClearRepositoriesMeteringArchiveRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_nodes") + 1 + len(strings.Join(r.NodeID, ",")) + 1 + len("_repositories_metering") + 1 + len(strconv.Itoa(*r.MaxArchiveVersion)))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.NodeID, ","))
+	path.WriteString("/")
+	path.WriteString("_repositories_metering")
+	path.WriteString("/")
+	path.WriteString(strconv.Itoa(*r.MaxArchiveVersion))
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithContext(v context.Context) func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithPretty() func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithHuman() func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithErrorTrace() func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithFilterPath(v ...string) func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithHeader(h map[string]string) func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesClearRepositoriesMeteringArchive) WithOpaqueID(s string) func(*NodesClearRepositoriesMeteringArchiveRequest) {
+	return func(r *NodesClearRepositoriesMeteringArchiveRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.get_metering_info.go b/esapi/api.nodes.get_metering_info.go
new file mode 100644
index 0000000000..2366a88a65
--- /dev/null
+++ b/esapi/api.nodes.get_metering_info.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.x: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newNodesGetMeteringInfoFunc(t Transport) NodesGetMeteringInfo {
+	return func(node_id []string, o ...func(*NodesGetMeteringInfoRequest)) (*Response, error) {
+		var r = NodesGetMeteringInfoRequest{NodeID: node_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// NodesGetMeteringInfo returns cluster repositories metering information.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-repositories-metering-api.html.
+//
+type NodesGetMeteringInfo func(node_id []string, o ...func(*NodesGetMeteringInfoRequest)) (*Response, error)
+
+// NodesGetMeteringInfoRequest configures the Nodes Get Metering Info API request.
+//
+type NodesGetMeteringInfoRequest struct {
+	NodeID []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r NodesGetMeteringInfoRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_nodes") + 1 + len(strings.Join(r.NodeID, ",")) + 1 + len("_repositories_metering"))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.NodeID, ","))
+	path.WriteString("/")
+	path.WriteString("_repositories_metering")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f NodesGetMeteringInfo) WithContext(v context.Context) func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f NodesGetMeteringInfo) WithPretty() func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f NodesGetMeteringInfo) WithHuman() func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f NodesGetMeteringInfo) WithErrorTrace() func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f NodesGetMeteringInfo) WithFilterPath(v ...string) func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesGetMeteringInfo) WithHeader(h map[string]string) func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesGetMeteringInfo) WithOpaqueID(s string) func(*NodesGetMeteringInfoRequest) {
+	return func(r *NodesGetMeteringInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.get_repositories_metering_info.go b/esapi/api.nodes.get_repositories_metering_info.go
new file mode 100644
index 0000000000..621c2b60fd
--- /dev/null
+++ b/esapi/api.nodes.get_repositories_metering_info.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newNodesGetRepositoriesMeteringInfoFunc(t Transport) NodesGetRepositoriesMeteringInfo {
+	return func(node_id []string, o ...func(*NodesGetRepositoriesMeteringInfoRequest)) (*Response, error) {
+		var r = NodesGetRepositoriesMeteringInfoRequest{NodeID: node_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// NodesGetRepositoriesMeteringInfo returns cluster repositories metering information.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-repositories-metering-api.html.
+//
+type NodesGetRepositoriesMeteringInfo func(node_id []string, o ...func(*NodesGetRepositoriesMeteringInfoRequest)) (*Response, error)
+
+// NodesGetRepositoriesMeteringInfoRequest configures the Nodes Get Repositories Metering Info API request.
+//
+type NodesGetRepositoriesMeteringInfoRequest struct {
+	NodeID []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r NodesGetRepositoriesMeteringInfoRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_nodes") + 1 + len(strings.Join(r.NodeID, ",")) + 1 + len("_repositories_metering"))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.NodeID, ","))
+	path.WriteString("/")
+	path.WriteString("_repositories_metering")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithContext(v context.Context) func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithPretty() func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithHuman() func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithErrorTrace() func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithFilterPath(v ...string) func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithHeader(h map[string]string) func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesGetRepositoriesMeteringInfo) WithOpaqueID(s string) func(*NodesGetRepositoriesMeteringInfoRequest) {
+	return func(r *NodesGetRepositoriesMeteringInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.hot_threads.go b/esapi/api.nodes.hot_threads.go
old mode 100755
new mode 100644
index 179a408c96..122e2b2cfd
--- a/esapi/api.nodes.hot_threads.go
+++ b/esapi/api.nodes.hot_threads.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,17 +41,19 @@ func newNodesHotThreadsFunc(t Transport) NodesHotThreads {
 
 // NodesHotThreads returns information about hot threads on each node in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-hot-threads.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-hot-threads.html.
 //
 type NodesHotThreads func(o ...func(*NodesHotThreadsRequest)) (*Response, error)
 
-// NodesHotThreadsRequest configures the Nodes  Hot Threads API request.
+// NodesHotThreadsRequest configures the Nodes Hot Threads API request.
 //
 type NodesHotThreadsRequest struct {
-	NodeID            []string
+	NodeID []string
+
 	IgnoreIdleThreads *bool
 	Interval          time.Duration
 	Snapshots         *int
+	Sort              string
 	Threads           *int
 	Timeout           time.Duration
 	DocumentType      string
@@ -43,6 +63,8 @@ type NodesHotThreadsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -83,6 +105,10 @@ func (r NodesHotThreadsRequest) Do(ctx context.Context, transport Transport) (*R
 		params["snapshots"] = strconv.FormatInt(int64(*r.Snapshots), 10)
 	}
 
+	if r.Sort != "" {
+		params["sort"] = r.Sort
+	}
+
 	if r.Threads != nil {
 		params["threads"] = strconv.FormatInt(int64(*r.Threads), 10)
 	}
@@ -111,7 +137,10 @@ func (r NodesHotThreadsRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -121,6 +150,18 @@ func (r NodesHotThreadsRequest) Do(ctx context.Context, transport Transport) (*R
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -179,6 +220,14 @@ func (f NodesHotThreads) WithSnapshots(v int) func(*NodesHotThreadsRequest) {
 	}
 }
 
+// WithSort - the sort order for 'cpu' type (default: total).
+//
+func (f NodesHotThreads) WithSort(v string) func(*NodesHotThreadsRequest) {
+	return func(r *NodesHotThreadsRequest) {
+		r.Sort = v
+	}
+}
+
 // WithThreads - specify the number of threads to provide information for (default: 3).
 //
 func (f NodesHotThreads) WithThreads(v int) func(*NodesHotThreadsRequest) {
@@ -234,3 +283,27 @@ func (f NodesHotThreads) WithFilterPath(v ...string) func(*NodesHotThreadsReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesHotThreads) WithHeader(h map[string]string) func(*NodesHotThreadsRequest) {
+	return func(r *NodesHotThreadsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesHotThreads) WithOpaqueID(s string) func(*NodesHotThreadsRequest) {
+	return func(r *NodesHotThreadsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.info.go b/esapi/api.nodes.info.go
old mode 100755
new mode 100644
index d284fc6b30..884c707095
--- a/esapi/api.nodes.info.go
+++ b/esapi/api.nodes.info.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,15 +41,16 @@ func newNodesInfoFunc(t Transport) NodesInfo {
 
 // NodesInfo returns information about nodes in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-info.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-info.html.
 //
 type NodesInfo func(o ...func(*NodesInfoRequest)) (*Response, error)
 
 // NodesInfoRequest configures the Nodes Info API request.
 //
 type NodesInfoRequest struct {
-	NodeID       []string
-	Metric       []string
+	Metric []string
+	NodeID []string
+
 	FlatSettings *bool
 	Timeout      time.Duration
 
@@ -40,6 +59,8 @@ type NodesInfoRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -92,7 +113,10 @@ func (r NodesInfoRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -102,6 +126,18 @@ func (r NodesInfoRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -128,7 +164,7 @@ func (f NodesInfo) WithContext(v context.Context) func(*NodesInfoRequest) {
 	}
 }
 
-// WithMetric - a list of metrics you wish returned. leave empty to return all..
+// WithMetric - a list of metrics you wish returned. leave empty to return all metrics..
 //
 func (f NodesInfo) WithMetric(v ...string) func(*NodesInfoRequest) {
 	return func(r *NodesInfoRequest) {
@@ -191,3 +227,27 @@ func (f NodesInfo) WithFilterPath(v ...string) func(*NodesInfoRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesInfo) WithHeader(h map[string]string) func(*NodesInfoRequest) {
+	return func(r *NodesInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesInfo) WithOpaqueID(s string) func(*NodesInfoRequest) {
+	return func(r *NodesInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.reload_secure_settings.go b/esapi/api.nodes.reload_secure_settings.go
old mode 100755
new mode 100644
index e698310075..07a073811b
--- a/esapi/api.nodes.reload_secure_settings.go
+++ b/esapi/api.nodes.reload_secure_settings.go
@@ -1,9 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"io"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -26,10 +45,13 @@ func newNodesReloadSecureSettingsFunc(t Transport) NodesReloadSecureSettings {
 //
 type NodesReloadSecureSettings func(o ...func(*NodesReloadSecureSettingsRequest)) (*Response, error)
 
-// NodesReloadSecureSettingsRequest configures the Nodes   Reload Secure Settings API request.
+// NodesReloadSecureSettingsRequest configures the Nodes Reload Secure Settings API request.
 //
 type NodesReloadSecureSettingsRequest struct {
-	NodeID  []string
+	Body io.Reader
+
+	NodeID []string
+
 	Timeout time.Duration
 
 	Pretty     bool
@@ -37,6 +59,8 @@ type NodesReloadSecureSettingsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -83,7 +107,10 @@ func (r NodesReloadSecureSettingsRequest) Do(ctx context.Context, transport Tran
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -93,6 +120,22 @@ func (r NodesReloadSecureSettingsRequest) Do(ctx context.Context, transport Tran
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -119,6 +162,14 @@ func (f NodesReloadSecureSettings) WithContext(v context.Context) func(*NodesRel
 	}
 }
 
+// WithBody - An object containing the password for the elasticsearch keystore.
+//
+func (f NodesReloadSecureSettings) WithBody(v io.Reader) func(*NodesReloadSecureSettingsRequest) {
+	return func(r *NodesReloadSecureSettingsRequest) {
+		r.Body = v
+	}
+}
+
 // WithNodeID - a list of node ids to span the reload/reinit call. should stay empty because reloading usually involves all cluster nodes..
 //
 func (f NodesReloadSecureSettings) WithNodeID(v ...string) func(*NodesReloadSecureSettingsRequest) {
@@ -166,3 +217,27 @@ func (f NodesReloadSecureSettings) WithFilterPath(v ...string) func(*NodesReload
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesReloadSecureSettings) WithHeader(h map[string]string) func(*NodesReloadSecureSettingsRequest) {
+	return func(r *NodesReloadSecureSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesReloadSecureSettings) WithOpaqueID(s string) func(*NodesReloadSecureSettingsRequest) {
+	return func(r *NodesReloadSecureSettingsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.stats.go b/esapi/api.nodes.stats.go
old mode 100755
new mode 100644
index cc5c528dfd..7039eb099e
--- a/esapi/api.nodes.stats.go
+++ b/esapi/api.nodes.stats.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,21 +41,23 @@ func newNodesStatsFunc(t Transport) NodesStats {
 
 // NodesStats returns statistical information about nodes in the cluster.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-stats.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-stats.html.
 //
 type NodesStats func(o ...func(*NodesStatsRequest)) (*Response, error)
 
 // NodesStatsRequest configures the Nodes Stats API request.
 //
 type NodesStatsRequest struct {
-	Metric                  []string
-	IndexMetric             []string
-	NodeID                  []string
+	IndexMetric []string
+	Metric      []string
+	NodeID      []string
+
 	CompletionFields        []string
 	FielddataFields         []string
 	Fields                  []string
 	Groups                  *bool
 	IncludeSegmentFileSizes *bool
+	IncludeUnloadedSegments *bool
 	Level                   string
 	Timeout                 time.Duration
 	Types                   []string
@@ -47,6 +67,8 @@ type NodesStatsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -101,6 +123,10 @@ func (r NodesStatsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["include_segment_file_sizes"] = strconv.FormatBool(*r.IncludeSegmentFileSizes)
 	}
 
+	if r.IncludeUnloadedSegments != nil {
+		params["include_unloaded_segments"] = strconv.FormatBool(*r.IncludeUnloadedSegments)
+	}
+
 	if r.Level != "" {
 		params["level"] = r.Level
 	}
@@ -129,7 +155,10 @@ func (r NodesStatsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -139,6 +168,18 @@ func (r NodesStatsRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -229,6 +270,14 @@ func (f NodesStats) WithIncludeSegmentFileSizes(v bool) func(*NodesStatsRequest)
 	}
 }
 
+// WithIncludeUnloadedSegments - if set to true segment stats will include stats for segments that are not currently loaded into memory.
+//
+func (f NodesStats) WithIncludeUnloadedSegments(v bool) func(*NodesStatsRequest) {
+	return func(r *NodesStatsRequest) {
+		r.IncludeUnloadedSegments = &v
+	}
+}
+
 // WithLevel - return indices stats aggregated at index, node or shard level.
 //
 func (f NodesStats) WithLevel(v string) func(*NodesStatsRequest) {
@@ -284,3 +333,27 @@ func (f NodesStats) WithFilterPath(v ...string) func(*NodesStatsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesStats) WithHeader(h map[string]string) func(*NodesStatsRequest) {
+	return func(r *NodesStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesStats) WithOpaqueID(s string) func(*NodesStatsRequest) {
+	return func(r *NodesStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.nodes.usage.go b/esapi/api.nodes.usage.go
old mode 100755
new mode 100644
index 48473bf052..d3f87f05eb
--- a/esapi/api.nodes.usage.go
+++ b/esapi/api.nodes.usage.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,15 +40,16 @@ func newNodesUsageFunc(t Transport) NodesUsage {
 
 // NodesUsage returns low-level information about REST actions usage on nodes.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-usage.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/cluster-nodes-usage.html.
 //
 type NodesUsage func(o ...func(*NodesUsageRequest)) (*Response, error)
 
 // NodesUsageRequest configures the Nodes Usage API request.
 //
 type NodesUsageRequest struct {
-	Metric  []string
-	NodeID  []string
+	Metric []string
+	NodeID []string
+
 	Timeout time.Duration
 
 	Pretty     bool
@@ -38,6 +57,8 @@ type NodesUsageRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -88,7 +109,10 @@ func (r NodesUsageRequest) Do(ctx context.Context, transport Transport) (*Respon
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -98,6 +122,18 @@ func (r NodesUsageRequest) Do(ctx context.Context, transport Transport) (*Respon
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -179,3 +215,27 @@ func (f NodesUsage) WithFilterPath(v ...string) func(*NodesUsageRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f NodesUsage) WithHeader(h map[string]string) func(*NodesUsageRequest) {
+	return func(r *NodesUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f NodesUsage) WithOpaqueID(s string) func(*NodesUsageRequest) {
+	return func(r *NodesUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.ping.go b/esapi/api.ping.go
old mode 100755
new mode 100644
index 4a9f1f2f7c..79a81e5927
--- a/esapi/api.ping.go
+++ b/esapi/api.ping.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 )
 
@@ -21,7 +39,7 @@ func newPingFunc(t Transport) Ping {
 
 // Ping returns whether the cluster is running.
 //
-// See full documentation at http://www.elastic.co/guide/.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html.
 //
 type Ping func(o ...func(*PingRequest)) (*Response, error)
 
@@ -33,6 +51,8 @@ type PingRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -68,7 +88,10 @@ func (r PingRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -78,6 +101,18 @@ func (r PingRequest) Do(ctx context.Context, transport Transport) (*Response, er
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -135,3 +170,27 @@ func (f Ping) WithFilterPath(v ...string) func(*PingRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Ping) WithHeader(h map[string]string) func(*PingRequest) {
+	return func(r *PingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Ping) WithOpaqueID(s string) func(*PingRequest) {
+	return func(r *PingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.put_script.go b/esapi/api.put_script.go
old mode 100755
new mode 100644
index 9bb5c8f64c..85cc7ae050
--- a/esapi/api.put_script.go
+++ b/esapi/api.put_script.go
@@ -1,17 +1,35 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 	"time"
 )
 
 func newPutScriptFunc(t Transport) PutScript {
 	return func(id string, body io.Reader, o ...func(*PutScriptRequest)) (*Response, error) {
-		var r = PutScriptRequest{DocumentID: id, Body: body}
+		var r = PutScriptRequest{ScriptID: id, Body: body}
 		for _, f := range o {
 			f(&r)
 		}
@@ -23,17 +41,19 @@ func newPutScriptFunc(t Transport) PutScript {
 
 // PutScript creates or updates a script.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html.
 //
 type PutScript func(id string, body io.Reader, o ...func(*PutScriptRequest)) (*Response, error)
 
 // PutScriptRequest configures the Put Script API request.
 //
 type PutScriptRequest struct {
-	DocumentID string
-	Body       io.Reader
+	ScriptID string
+
+	Body io.Reader
 
 	ScriptContext string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -42,6 +62,8 @@ type PutScriptRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -56,11 +78,11 @@ func (r PutScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 
 	method = "PUT"
 
-	path.Grow(1 + len("_scripts") + 1 + len(r.DocumentID) + 1 + len(r.ScriptContext))
+	path.Grow(1 + len("_scripts") + 1 + len(r.ScriptID) + 1 + len(r.ScriptContext))
 	path.WriteString("/")
 	path.WriteString("_scripts")
 	path.WriteString("/")
-	path.WriteString(r.DocumentID)
+	path.WriteString(r.ScriptID)
 	if r.ScriptContext != "" {
 		path.WriteString("/")
 		path.WriteString(r.ScriptContext)
@@ -96,7 +118,10 @@ func (r PutScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -110,6 +135,18 @@ func (r PutScriptRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,3 +228,27 @@ func (f PutScript) WithFilterPath(v ...string) func(*PutScriptRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f PutScript) WithHeader(h map[string]string) func(*PutScriptRequest) {
+	return func(r *PutScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f PutScript) WithOpaqueID(s string) func(*PutScriptRequest) {
+	return func(r *PutScriptRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.rank_eval.go b/esapi/api.rank_eval.go
old mode 100755
new mode 100644
index ed33a98685..231af553e7
--- a/esapi/api.rank_eval.go
+++ b/esapi/api.rank_eval.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -31,17 +49,21 @@ type RankEval func(body io.Reader, o ...func(*RankEvalRequest)) (*Response, erro
 //
 type RankEvalRequest struct {
 	Index []string
-	Body  io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices    *bool
 	ExpandWildcards   string
 	IgnoreUnavailable *bool
+	SearchType        string
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -54,7 +76,7 @@ func (r RankEvalRequest) Do(ctx context.Context, transport Transport) (*Response
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_rank_eval"))
 	if len(r.Index) > 0 {
@@ -78,6 +100,10 @@ func (r RankEvalRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
 	}
 
+	if r.SearchType != "" {
+		params["search_type"] = r.SearchType
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -94,7 +120,10 @@ func (r RankEvalRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -108,6 +137,18 @@ func (r RankEvalRequest) Do(ctx context.Context, transport Transport) (*Response
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -166,6 +207,14 @@ func (f RankEval) WithIgnoreUnavailable(v bool) func(*RankEvalRequest) {
 	}
 }
 
+// WithSearchType - search operation type.
+//
+func (f RankEval) WithSearchType(v string) func(*RankEvalRequest) {
+	return func(r *RankEvalRequest) {
+		r.SearchType = v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f RankEval) WithPretty() func(*RankEvalRequest) {
@@ -197,3 +246,27 @@ func (f RankEval) WithFilterPath(v ...string) func(*RankEvalRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RankEval) WithHeader(h map[string]string) func(*RankEvalRequest) {
+	return func(r *RankEvalRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RankEval) WithOpaqueID(s string) func(*RankEvalRequest) {
+	return func(r *RankEvalRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.reindex.go b/esapi/api.reindex.go
old mode 100755
new mode 100644
index cb83590c1e..aaff7d3cd2
--- a/esapi/api.reindex.go
+++ b/esapi/api.reindex.go
@@ -1,10 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"fmt"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -35,10 +54,11 @@ type Reindex func(body io.Reader, o ...func(*ReindexRequest)) (*Response, error)
 type ReindexRequest struct {
 	Body io.Reader
 
+	MaxDocs             *int
 	Refresh             *bool
 	RequestsPerSecond   *int
 	Scroll              time.Duration
-	Slices              *int
+	Slices              interface{}
 	Timeout             time.Duration
 	WaitForActiveShards string
 	WaitForCompletion   *bool
@@ -48,6 +68,8 @@ type ReindexRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -67,6 +89,10 @@ func (r ReindexRequest) Do(ctx context.Context, transport Transport) (*Response,
 
 	params = make(map[string]string)
 
+	if r.MaxDocs != nil {
+		params["max_docs"] = strconv.FormatInt(int64(*r.MaxDocs), 10)
+	}
+
 	if r.Refresh != nil {
 		params["refresh"] = strconv.FormatBool(*r.Refresh)
 	}
@@ -80,7 +106,7 @@ func (r ReindexRequest) Do(ctx context.Context, transport Transport) (*Response,
 	}
 
 	if r.Slices != nil {
-		params["slices"] = strconv.FormatInt(int64(*r.Slices), 10)
+		params["slices"] = fmt.Sprintf("%v", r.Slices)
 	}
 
 	if r.Timeout != 0 {
@@ -111,7 +137,10 @@ func (r ReindexRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -125,6 +154,18 @@ func (r ReindexRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -151,7 +192,15 @@ func (f Reindex) WithContext(v context.Context) func(*ReindexRequest) {
 	}
 }
 
-// WithRefresh - should the effected indexes be refreshed?.
+// WithMaxDocs - maximum number of documents to process (default: all documents).
+//
+func (f Reindex) WithMaxDocs(v int) func(*ReindexRequest) {
+	return func(r *ReindexRequest) {
+		r.MaxDocs = &v
+	}
+}
+
+// WithRefresh - should the affected indexes be refreshed?.
 //
 func (f Reindex) WithRefresh(v bool) func(*ReindexRequest) {
 	return func(r *ReindexRequest) {
@@ -175,11 +224,11 @@ func (f Reindex) WithScroll(v time.Duration) func(*ReindexRequest) {
 	}
 }
 
-// WithSlices - the number of slices this task should be divided into. defaults to 1 meaning the task isn't sliced into subtasks..
+// WithSlices - the number of slices this task should be divided into. defaults to 1, meaning the task isn't sliced into subtasks. can be set to `auto`..
 //
-func (f Reindex) WithSlices(v int) func(*ReindexRequest) {
+func (f Reindex) WithSlices(v interface{}) func(*ReindexRequest) {
 	return func(r *ReindexRequest) {
-		r.Slices = &v
+		r.Slices = v
 	}
 }
 
@@ -238,3 +287,27 @@ func (f Reindex) WithFilterPath(v ...string) func(*ReindexRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Reindex) WithHeader(h map[string]string) func(*ReindexRequest) {
+	return func(r *ReindexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Reindex) WithOpaqueID(s string) func(*ReindexRequest) {
+	return func(r *ReindexRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.reindex_rethrottle.go b/esapi/api.reindex_rethrottle.go
old mode 100755
new mode 100644
index 4d7031e151..61637df5a2
--- a/esapi/api.reindex_rethrottle.go
+++ b/esapi/api.reindex_rethrottle.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -29,7 +47,8 @@ type ReindexRethrottle func(task_id string, requests_per_second *int, o ...func(
 // ReindexRethrottleRequest configures the Reindex Rethrottle API request.
 //
 type ReindexRethrottleRequest struct {
-	TaskID            string
+	TaskID string
+
 	RequestsPerSecond *int
 
 	Pretty     bool
@@ -37,6 +56,8 @@ type ReindexRethrottleRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -81,7 +102,10 @@ func (r ReindexRethrottleRequest) Do(ctx context.Context, transport Transport) (
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -91,6 +115,18 @@ func (r ReindexRethrottleRequest) Do(ctx context.Context, transport Transport) (
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -156,3 +192,27 @@ func (f ReindexRethrottle) WithFilterPath(v ...string) func(*ReindexRethrottleRe
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ReindexRethrottle) WithHeader(h map[string]string) func(*ReindexRethrottleRequest) {
+	return func(r *ReindexRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ReindexRethrottle) WithOpaqueID(s string) func(*ReindexRethrottleRequest) {
+	return func(r *ReindexRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.render_search_template.go b/esapi/api.render_search_template.go
old mode 100755
new mode 100644
index 905c8cd863..c4b14197a0
--- a/esapi/api.render_search_template.go
+++ b/esapi/api.render_search_template.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 )
 
@@ -22,21 +40,24 @@ func newRenderSearchTemplateFunc(t Transport) RenderSearchTemplate {
 
 // RenderSearchTemplate allows to use the Mustache language to pre-render a search definition.
 //
-// See full documentation at http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/search-template.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/render-search-template-api.html.
 //
 type RenderSearchTemplate func(o ...func(*RenderSearchTemplateRequest)) (*Response, error)
 
 // RenderSearchTemplateRequest configures the Render Search Template API request.
 //
 type RenderSearchTemplateRequest struct {
-	DocumentID string
-	Body       io.Reader
+	TemplateID string
+
+	Body io.Reader
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -49,16 +70,16 @@ func (r RenderSearchTemplateRequest) Do(ctx context.Context, transport Transport
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
-	path.Grow(1 + len("_render") + 1 + len("template") + 1 + len(r.DocumentID))
+	path.Grow(1 + len("_render") + 1 + len("template") + 1 + len(r.TemplateID))
 	path.WriteString("/")
 	path.WriteString("_render")
 	path.WriteString("/")
 	path.WriteString("template")
-	if r.DocumentID != "" {
+	if r.TemplateID != "" {
 		path.WriteString("/")
-		path.WriteString(r.DocumentID)
+		path.WriteString(r.TemplateID)
 	}
 
 	params = make(map[string]string)
@@ -79,7 +100,10 @@ func (r RenderSearchTemplateRequest) Do(ctx context.Context, transport Transport
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -93,6 +117,18 @@ func (r RenderSearchTemplateRequest) Do(ctx context.Context, transport Transport
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -119,19 +155,19 @@ func (f RenderSearchTemplate) WithContext(v context.Context) func(*RenderSearchT
 	}
 }
 
-// WithDocumentID - the ID of the stored search template.
+// WithBody - The search definition template and its params.
 //
-func (f RenderSearchTemplate) WithDocumentID(v string) func(*RenderSearchTemplateRequest) {
+func (f RenderSearchTemplate) WithBody(v io.Reader) func(*RenderSearchTemplateRequest) {
 	return func(r *RenderSearchTemplateRequest) {
-		r.DocumentID = v
+		r.Body = v
 	}
 }
 
-// WithBody - The search definition template and its params.
+// WithTemplateID - the ID of the stored search template.
 //
-func (f RenderSearchTemplate) WithBody(v io.Reader) func(*RenderSearchTemplateRequest) {
+func (f RenderSearchTemplate) WithTemplateID(v string) func(*RenderSearchTemplateRequest) {
 	return func(r *RenderSearchTemplateRequest) {
-		r.Body = v
+		r.TemplateID = v
 	}
 }
 
@@ -166,3 +202,27 @@ func (f RenderSearchTemplate) WithFilterPath(v ...string) func(*RenderSearchTemp
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RenderSearchTemplate) WithHeader(h map[string]string) func(*RenderSearchTemplateRequest) {
+	return func(r *RenderSearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RenderSearchTemplate) WithOpaqueID(s string) func(*RenderSearchTemplateRequest) {
+	return func(r *RenderSearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.scripts_painless_execute.go b/esapi/api.scripts_painless_execute.go
old mode 100755
new mode 100644
index e4edb0b591..e9c005c357
--- a/esapi/api.scripts_painless_execute.go
+++ b/esapi/api.scripts_painless_execute.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strings"
 )
 
@@ -22,6 +40,8 @@ func newScriptsPainlessExecuteFunc(t Transport) ScriptsPainlessExecute {
 
 // ScriptsPainlessExecute allows an arbitrary script to be executed and a result to be returned
 //
+// This API is experimental.
+//
 // See full documentation at https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html.
 //
 type ScriptsPainlessExecute func(o ...func(*ScriptsPainlessExecuteRequest)) (*Response, error)
@@ -36,6 +56,8 @@ type ScriptsPainlessExecuteRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -48,7 +70,7 @@ func (r ScriptsPainlessExecuteRequest) Do(ctx context.Context, transport Transpo
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(len("/_scripts/painless/_execute"))
 	path.WriteString("/_scripts/painless/_execute")
@@ -71,7 +93,10 @@ func (r ScriptsPainlessExecuteRequest) Do(ctx context.Context, transport Transpo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -85,6 +110,18 @@ func (r ScriptsPainlessExecuteRequest) Do(ctx context.Context, transport Transpo
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -150,3 +187,27 @@ func (f ScriptsPainlessExecute) WithFilterPath(v ...string) func(*ScriptsPainles
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ScriptsPainlessExecute) WithHeader(h map[string]string) func(*ScriptsPainlessExecuteRequest) {
+	return func(r *ScriptsPainlessExecuteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ScriptsPainlessExecute) WithOpaqueID(s string) func(*ScriptsPainlessExecuteRequest) {
+	return func(r *ScriptsPainlessExecuteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.scroll.go b/esapi/api.scroll.go
old mode 100755
new mode 100644
index df6890e136..9f546fab93
--- a/esapi/api.scroll.go
+++ b/esapi/api.scroll.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newScrollFunc(t Transport) Scroll {
 
 // Scroll allows to retrieve a large numbers of results from a single search request.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-body.html#request-body-search-scroll.
 //
 type Scroll func(o ...func(*ScrollRequest)) (*Response, error)
 
@@ -33,7 +51,8 @@ type Scroll func(o ...func(*ScrollRequest)) (*Response, error)
 type ScrollRequest struct {
 	Body io.Reader
 
-	ScrollID           string
+	ScrollID string
+
 	RestTotalHitsAsInt *bool
 	Scroll             time.Duration
 
@@ -42,6 +61,8 @@ type ScrollRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -54,17 +75,10 @@ func (r ScrollRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
-	path.Grow(1 + len("_search") + 1 + len("scroll") + 1 + len(r.ScrollID))
-	path.WriteString("/")
-	path.WriteString("_search")
-	path.WriteString("/")
-	path.WriteString("scroll")
-	if r.ScrollID != "" {
-		path.WriteString("/")
-		path.WriteString(r.ScrollID)
-	}
+	path.Grow(len("/_search/scroll"))
+	path.WriteString("/_search/scroll")
 
 	params = make(map[string]string)
 
@@ -96,7 +110,10 @@ func (r ScrollRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -110,6 +127,18 @@ func (r ScrollRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -136,19 +165,19 @@ func (f Scroll) WithContext(v context.Context) func(*ScrollRequest) {
 	}
 }
 
-// WithScrollID - the scroll ID.
+// WithBody - The scroll ID if not passed by URL or query parameter..
 //
-func (f Scroll) WithScrollID(v string) func(*ScrollRequest) {
+func (f Scroll) WithBody(v io.Reader) func(*ScrollRequest) {
 	return func(r *ScrollRequest) {
-		r.ScrollID = v
+		r.Body = v
 	}
 }
 
-// WithBody - The scroll ID if not passed by URL or query parameter..
+// WithScrollID - the scroll ID.
 //
-func (f Scroll) WithBody(v io.Reader) func(*ScrollRequest) {
+func (f Scroll) WithScrollID(v string) func(*ScrollRequest) {
 	return func(r *ScrollRequest) {
-		r.Body = v
+		r.ScrollID = v
 	}
 }
 
@@ -199,3 +228,27 @@ func (f Scroll) WithFilterPath(v ...string) func(*ScrollRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Scroll) WithHeader(h map[string]string) func(*ScrollRequest) {
+	return func(r *ScrollRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Scroll) WithOpaqueID(s string) func(*ScrollRequest) {
+	return func(r *ScrollRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.search.go b/esapi/api.search.go
old mode 100755
new mode 100644
index 90cad4f74b..c02be885c4
--- a/esapi/api.search.go
+++ b/esapi/api.search.go
@@ -1,4 +1,21 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
@@ -6,6 +23,7 @@ import (
 	"context"
 	"fmt"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -25,7 +43,7 @@ func newSearchFunc(t Transport) Search {
 
 // Search returns results matching a query.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-search.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-search.html.
 //
 type Search func(o ...func(*SearchRequest)) (*Response, error)
 
@@ -34,7 +52,8 @@ type Search func(o ...func(*SearchRequest)) (*Response, error)
 type SearchRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices             *bool
 	AllowPartialSearchResults  *bool
@@ -52,6 +71,7 @@ type SearchRequest struct {
 	IgnoreUnavailable          *bool
 	Lenient                    *bool
 	MaxConcurrentShardRequests *int
+	MinCompatibleShardNode     string
 	Preference                 string
 	PreFilterShardSize         *int
 	Query                      string
@@ -84,6 +104,8 @@ type SearchRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -96,7 +118,7 @@ func (r SearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_search"))
 	if len(r.Index) > 0 {
@@ -176,6 +198,10 @@ func (r SearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["max_concurrent_shard_requests"] = strconv.FormatInt(int64(*r.MaxConcurrentShardRequests), 10)
 	}
 
+	if r.MinCompatibleShardNode != "" {
+		params["min_compatible_shard_node"] = r.MinCompatibleShardNode
+	}
+
 	if r.Preference != "" {
 		params["preference"] = r.Preference
 	}
@@ -296,7 +322,10 @@ func (r SearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -310,6 +339,18 @@ func (r SearchRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -336,6 +377,14 @@ func (f Search) WithContext(v context.Context) func(*SearchRequest) {
 	}
 }
 
+// WithBody - The search definition using the Query DSL.
+//
+func (f Search) WithBody(v io.Reader) func(*SearchRequest) {
+	return func(r *SearchRequest) {
+		r.Body = v
+	}
+}
+
 // WithIndex - a list of index names to search; use _all to perform the operation on all indices.
 //
 func (f Search) WithIndex(v ...string) func(*SearchRequest) {
@@ -352,14 +401,6 @@ func (f Search) WithDocumentType(v ...string) func(*SearchRequest) {
 	}
 }
 
-// WithBody - The search definition using the Query DSL.
-//
-func (f Search) WithBody(v io.Reader) func(*SearchRequest) {
-	return func(r *SearchRequest) {
-		r.Body = v
-	}
-}
-
 // WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
 //
 func (f Search) WithAllowNoIndices(v bool) func(*SearchRequest) {
@@ -488,6 +529,14 @@ func (f Search) WithMaxConcurrentShardRequests(v int) func(*SearchRequest) {
 	}
 }
 
+// WithMinCompatibleShardNode - the minimum compatible version that all shards involved in search should have for this request to be successful.
+//
+func (f Search) WithMinCompatibleShardNode(v string) func(*SearchRequest) {
+	return func(r *SearchRequest) {
+		r.MinCompatibleShardNode = v
+	}
+}
+
 // WithPreference - specify the node or shard the operation should be performed on (default: random).
 //
 func (f Search) WithPreference(v string) func(*SearchRequest) {
@@ -496,7 +545,7 @@ func (f Search) WithPreference(v string) func(*SearchRequest) {
 	}
 }
 
-// WithPreFilterShardSize - a threshold that enforces a pre-filter roundtrip to prefilter search shards based on query rewriting if the number of shards the search request expands to exceeds the threshold. this filter roundtrip can limit the number of shards significantly if for instance a shard can not match any documents based on it's rewrite method ie. if date filters are mandatory to match but the shard bounds and the query are disjoint..
+// WithPreFilterShardSize - a threshold that enforces a pre-filter roundtrip to prefilter search shards based on query rewriting if the number of shards the search request expands to exceeds the threshold. this filter roundtrip can limit the number of shards significantly if for instance a shard can not match any documents based on its rewrite method ie. if date filters are mandatory to match but the shard bounds and the query are disjoint..
 //
 func (f Search) WithPreFilterShardSize(v int) func(*SearchRequest) {
 	return func(r *SearchRequest) {
@@ -727,3 +776,27 @@ func (f Search) WithFilterPath(v ...string) func(*SearchRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Search) WithHeader(h map[string]string) func(*SearchRequest) {
+	return func(r *SearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Search) WithOpaqueID(s string) func(*SearchRequest) {
+	return func(r *SearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.search_mvt.go b/esapi/api.search_mvt.go
new file mode 100644
index 0000000000..f6985742a4
--- /dev/null
+++ b/esapi/api.search_mvt.go
@@ -0,0 +1,312 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newSearchMvtFunc(t Transport) SearchMvt {
+	return func(index []string, field string, zoom *int, x *int, y *int, o ...func(*SearchMvtRequest)) (*Response, error) {
+		var r = SearchMvtRequest{Index: index, X: x, Y: y, Field: field, Zoom: zoom}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchMvt searches a vector tile for geospatial values. Returns results as a binary Mapbox vector tile.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-vector-tile-api.html.
+//
+type SearchMvt func(index []string, field string, zoom *int, x *int, y *int, o ...func(*SearchMvtRequest)) (*Response, error)
+
+// SearchMvtRequest configures the Search Mvt API request.
+//
+type SearchMvtRequest struct {
+	Index []string
+
+	Body io.Reader
+
+	Field string
+	X     *int
+	Y     *int
+	Zoom  *int
+
+	ExactBounds    *bool
+	Extent         *int
+	GridPrecision  *int
+	GridType       string
+	Size           *int
+	TrackTotalHits interface{}
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchMvtRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_mvt") + 1 + len(r.Field) + 1 + len(strconv.Itoa(*r.Zoom)) + 1 + len(strconv.Itoa(*r.X)) + 1 + len(strconv.Itoa(*r.Y)))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_mvt")
+	path.WriteString("/")
+	path.WriteString(r.Field)
+	path.WriteString("/")
+	path.WriteString(strconv.Itoa(*r.Zoom))
+	path.WriteString("/")
+	path.WriteString(strconv.Itoa(*r.X))
+	path.WriteString("/")
+	path.WriteString(strconv.Itoa(*r.Y))
+
+	params = make(map[string]string)
+
+	if r.ExactBounds != nil {
+		params["exact_bounds"] = strconv.FormatBool(*r.ExactBounds)
+	}
+
+	if r.Extent != nil {
+		params["extent"] = strconv.FormatInt(int64(*r.Extent), 10)
+	}
+
+	if r.GridPrecision != nil {
+		params["grid_precision"] = strconv.FormatInt(int64(*r.GridPrecision), 10)
+	}
+
+	if r.GridType != "" {
+		params["grid_type"] = r.GridType
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.TrackTotalHits != nil {
+		params["track_total_hits"] = fmt.Sprintf("%v", r.TrackTotalHits)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchMvt) WithContext(v context.Context) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Search request body..
+//
+func (f SearchMvt) WithBody(v io.Reader) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.Body = v
+	}
+}
+
+// WithExactBounds - if false, the meta layer's feature is the bounding box of the tile. if true, the meta layer's feature is a bounding box resulting from a `geo_bounds` aggregation..
+//
+func (f SearchMvt) WithExactBounds(v bool) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.ExactBounds = &v
+	}
+}
+
+// WithExtent - size, in pixels, of a side of the vector tile..
+//
+func (f SearchMvt) WithExtent(v int) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.Extent = &v
+	}
+}
+
+// WithGridPrecision - additional zoom levels available through the aggs layer. accepts 0-8..
+//
+func (f SearchMvt) WithGridPrecision(v int) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.GridPrecision = &v
+	}
+}
+
+// WithGridType - determines the geometry type for features in the aggs layer..
+//
+func (f SearchMvt) WithGridType(v string) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.GridType = v
+	}
+}
+
+// WithSize - maximum number of features to return in the hits layer. accepts 0-10000..
+//
+func (f SearchMvt) WithSize(v int) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.Size = &v
+	}
+}
+
+// WithTrackTotalHits - indicate if the number of documents that match the query should be tracked. a number can also be specified, to accurately track the total hit count up to the number..
+//
+func (f SearchMvt) WithTrackTotalHits(v interface{}) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.TrackTotalHits = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchMvt) WithPretty() func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchMvt) WithHuman() func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchMvt) WithErrorTrace() func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchMvt) WithFilterPath(v ...string) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchMvt) WithHeader(h map[string]string) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchMvt) WithOpaqueID(s string) func(*SearchMvtRequest) {
+	return func(r *SearchMvtRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.search_shards.go b/esapi/api.search_shards.go
old mode 100755
new mode 100644
index 84368a1cf6..13555fc354
--- a/esapi/api.search_shards.go
+++ b/esapi/api.search_shards.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -22,7 +40,7 @@ func newSearchShardsFunc(t Transport) SearchShards {
 
 // SearchShards returns information about the indices and shards that a search request would be executed against.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/search-shards.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/search-shards.html.
 //
 type SearchShards func(o ...func(*SearchShardsRequest)) (*Response, error)
 
@@ -43,6 +61,8 @@ type SearchShardsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -55,7 +75,7 @@ func (r SearchShardsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_search_shards"))
 	if len(r.Index) > 0 {
@@ -107,7 +127,10 @@ func (r SearchShardsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -117,6 +140,18 @@ func (r SearchShardsRequest) Do(ctx context.Context, transport Transport) (*Resp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -230,3 +265,27 @@ func (f SearchShards) WithFilterPath(v ...string) func(*SearchShardsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchShards) WithHeader(h map[string]string) func(*SearchShardsRequest) {
+	return func(r *SearchShardsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchShards) WithOpaqueID(s string) func(*SearchShardsRequest) {
+	return func(r *SearchShardsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.search_template.go b/esapi/api.search_template.go
old mode 100755
new mode 100644
index 491775193f..2d148b906a
--- a/esapi/api.search_template.go
+++ b/esapi/api.search_template.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newSearchTemplateFunc(t Transport) SearchTemplate {
 
 // SearchTemplate allows to use the Mustache language to pre-render a search definition.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html.
 //
 type SearchTemplate func(body io.Reader, o ...func(*SearchTemplateRequest)) (*Response, error)
 
@@ -33,7 +51,8 @@ type SearchTemplate func(body io.Reader, o ...func(*SearchTemplateRequest)) (*Re
 type SearchTemplateRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices        *bool
 	CcsMinimizeRoundtrips *bool
@@ -54,6 +73,8 @@ type SearchTemplateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -66,7 +87,7 @@ func (r SearchTemplateRequest) Do(ctx context.Context, transport Transport) (*Re
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_search") + 1 + len("template"))
 	if len(r.Index) > 0 {
@@ -152,7 +173,10 @@ func (r SearchTemplateRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -166,6 +190,18 @@ func (r SearchTemplateRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -343,3 +379,27 @@ func (f SearchTemplate) WithFilterPath(v ...string) func(*SearchTemplateRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchTemplate) WithHeader(h map[string]string) func(*SearchTemplateRequest) {
+	return func(r *SearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchTemplate) WithOpaqueID(s string) func(*SearchTemplateRequest) {
+	return func(r *SearchTemplateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.shutdown.delete_node.go b/esapi/api.shutdown.delete_node.go
new file mode 100644
index 0000000000..840f54f6c6
--- /dev/null
+++ b/esapi/api.shutdown.delete_node.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newShutdownDeleteNodeFunc(t Transport) ShutdownDeleteNode {
+	return func(node_id string, o ...func(*ShutdownDeleteNodeRequest)) (*Response, error) {
+		var r = ShutdownDeleteNodeRequest{NodeID: node_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ShutdownDeleteNode removes a node from the shutdown list. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current.
+//
+type ShutdownDeleteNode func(node_id string, o ...func(*ShutdownDeleteNodeRequest)) (*Response, error)
+
+// ShutdownDeleteNodeRequest configures the Shutdown Delete Node API request.
+//
+type ShutdownDeleteNodeRequest struct {
+	NodeID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ShutdownDeleteNodeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_nodes") + 1 + len(r.NodeID) + 1 + len("shutdown"))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(r.NodeID)
+	path.WriteString("/")
+	path.WriteString("shutdown")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ShutdownDeleteNode) WithContext(v context.Context) func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ShutdownDeleteNode) WithPretty() func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ShutdownDeleteNode) WithHuman() func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ShutdownDeleteNode) WithErrorTrace() func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ShutdownDeleteNode) WithFilterPath(v ...string) func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ShutdownDeleteNode) WithHeader(h map[string]string) func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ShutdownDeleteNode) WithOpaqueID(s string) func(*ShutdownDeleteNodeRequest) {
+	return func(r *ShutdownDeleteNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.shutdown.get_node.go b/esapi/api.shutdown.get_node.go
new file mode 100644
index 0000000000..a034272ddd
--- /dev/null
+++ b/esapi/api.shutdown.get_node.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newShutdownGetNodeFunc(t Transport) ShutdownGetNode {
+	return func(o ...func(*ShutdownGetNodeRequest)) (*Response, error) {
+		var r = ShutdownGetNodeRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ShutdownGetNode retrieve status of a node or nodes that are currently marked as shutting down. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current.
+//
+type ShutdownGetNode func(o ...func(*ShutdownGetNodeRequest)) (*Response, error)
+
+// ShutdownGetNodeRequest configures the Shutdown Get Node API request.
+//
+type ShutdownGetNodeRequest struct {
+	NodeID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ShutdownGetNodeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_nodes") + 1 + len(r.NodeID) + 1 + len("shutdown"))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	if r.NodeID != "" {
+		path.WriteString("/")
+		path.WriteString(r.NodeID)
+	}
+	path.WriteString("/")
+	path.WriteString("shutdown")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ShutdownGetNode) WithContext(v context.Context) func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithNodeID - which node for which to retrieve the shutdown status.
+//
+func (f ShutdownGetNode) WithNodeID(v string) func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.NodeID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ShutdownGetNode) WithPretty() func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ShutdownGetNode) WithHuman() func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ShutdownGetNode) WithErrorTrace() func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ShutdownGetNode) WithFilterPath(v ...string) func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ShutdownGetNode) WithHeader(h map[string]string) func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ShutdownGetNode) WithOpaqueID(s string) func(*ShutdownGetNodeRequest) {
+	return func(r *ShutdownGetNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.shutdown.put_node.go b/esapi/api.shutdown.put_node.go
new file mode 100644
index 0000000000..c26c093dca
--- /dev/null
+++ b/esapi/api.shutdown.put_node.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newShutdownPutNodeFunc(t Transport) ShutdownPutNode {
+	return func(body io.Reader, node_id string, o ...func(*ShutdownPutNodeRequest)) (*Response, error) {
+		var r = ShutdownPutNodeRequest{Body: body, NodeID: node_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ShutdownPutNode adds a node to be shut down. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current.
+//
+type ShutdownPutNode func(body io.Reader, node_id string, o ...func(*ShutdownPutNodeRequest)) (*Response, error)
+
+// ShutdownPutNodeRequest configures the Shutdown Put Node API request.
+//
+type ShutdownPutNodeRequest struct {
+	Body io.Reader
+
+	NodeID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ShutdownPutNodeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_nodes") + 1 + len(r.NodeID) + 1 + len("shutdown"))
+	path.WriteString("/")
+	path.WriteString("_nodes")
+	path.WriteString("/")
+	path.WriteString(r.NodeID)
+	path.WriteString("/")
+	path.WriteString("shutdown")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ShutdownPutNode) WithContext(v context.Context) func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ShutdownPutNode) WithPretty() func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ShutdownPutNode) WithHuman() func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ShutdownPutNode) WithErrorTrace() func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ShutdownPutNode) WithFilterPath(v ...string) func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ShutdownPutNode) WithHeader(h map[string]string) func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ShutdownPutNode) WithOpaqueID(s string) func(*ShutdownPutNodeRequest) {
+	return func(r *ShutdownPutNodeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.cleanup_repository.go b/esapi/api.snapshot.cleanup_repository.go
new file mode 100644
index 0000000000..2f11f19447
--- /dev/null
+++ b/esapi/api.snapshot.cleanup_repository.go
@@ -0,0 +1,231 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newSnapshotCleanupRepositoryFunc(t Transport) SnapshotCleanupRepository {
+	return func(repository string, o ...func(*SnapshotCleanupRepositoryRequest)) (*Response, error) {
+		var r = SnapshotCleanupRepositoryRequest{Repository: repository}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SnapshotCleanupRepository removes stale data from repository.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/clean-up-snapshot-repo-api.html.
+//
+type SnapshotCleanupRepository func(repository string, o ...func(*SnapshotCleanupRepositoryRequest)) (*Response, error)
+
+// SnapshotCleanupRepositoryRequest configures the Snapshot Cleanup Repository API request.
+//
+type SnapshotCleanupRepositoryRequest struct {
+	Repository string
+
+	MasterTimeout time.Duration
+	Timeout       time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SnapshotCleanupRepositoryRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_snapshot") + 1 + len(r.Repository) + 1 + len("_cleanup"))
+	path.WriteString("/")
+	path.WriteString("_snapshot")
+	path.WriteString("/")
+	path.WriteString(r.Repository)
+	path.WriteString("/")
+	path.WriteString("_cleanup")
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SnapshotCleanupRepository) WithContext(v context.Context) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f SnapshotCleanupRepository) WithMasterTimeout(v time.Duration) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f SnapshotCleanupRepository) WithTimeout(v time.Duration) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SnapshotCleanupRepository) WithPretty() func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SnapshotCleanupRepository) WithHuman() func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SnapshotCleanupRepository) WithErrorTrace() func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SnapshotCleanupRepository) WithFilterPath(v ...string) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotCleanupRepository) WithHeader(h map[string]string) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotCleanupRepository) WithOpaqueID(s string) func(*SnapshotCleanupRepositoryRequest) {
+	return func(r *SnapshotCleanupRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.clone.go b/esapi/api.snapshot.clone.go
new file mode 100644
index 0000000000..eae3e6b125
--- /dev/null
+++ b/esapi/api.snapshot.clone.go
@@ -0,0 +1,231 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newSnapshotCloneFunc(t Transport) SnapshotClone {
+	return func(repository string, snapshot string, body io.Reader, target_snapshot string, o ...func(*SnapshotCloneRequest)) (*Response, error) {
+		var r = SnapshotCloneRequest{Repository: repository, Snapshot: snapshot, Body: body, TargetSnapshot: target_snapshot}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SnapshotClone clones indices from one snapshot into another snapshot in the same repository.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+//
+type SnapshotClone func(repository string, snapshot string, body io.Reader, target_snapshot string, o ...func(*SnapshotCloneRequest)) (*Response, error)
+
+// SnapshotCloneRequest configures the Snapshot Clone API request.
+//
+type SnapshotCloneRequest struct {
+	Body io.Reader
+
+	Repository     string
+	Snapshot       string
+	TargetSnapshot string
+
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SnapshotCloneRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_snapshot") + 1 + len(r.Repository) + 1 + len(r.Snapshot) + 1 + len("_clone") + 1 + len(r.TargetSnapshot))
+	path.WriteString("/")
+	path.WriteString("_snapshot")
+	path.WriteString("/")
+	path.WriteString(r.Repository)
+	path.WriteString("/")
+	path.WriteString(r.Snapshot)
+	path.WriteString("/")
+	path.WriteString("_clone")
+	path.WriteString("/")
+	path.WriteString(r.TargetSnapshot)
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SnapshotClone) WithContext(v context.Context) func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f SnapshotClone) WithMasterTimeout(v time.Duration) func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SnapshotClone) WithPretty() func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SnapshotClone) WithHuman() func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SnapshotClone) WithErrorTrace() func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SnapshotClone) WithFilterPath(v ...string) func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotClone) WithHeader(h map[string]string) func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotClone) WithOpaqueID(s string) func(*SnapshotCloneRequest) {
+	return func(r *SnapshotCloneRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.create.go b/esapi/api.snapshot.create.go
old mode 100755
new mode 100644
index 51ccedb72d..239efda4a6
--- a/esapi/api.snapshot.create.go
+++ b/esapi/api.snapshot.create.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newSnapshotCreateFunc(t Transport) SnapshotCreate {
 
 // SnapshotCreate creates a snapshot in a repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotCreate func(repository string, snapshot string, o ...func(*SnapshotCreateRequest)) (*Response, error)
 
@@ -33,8 +51,9 @@ type SnapshotCreate func(repository string, snapshot string, o ...func(*Snapshot
 type SnapshotCreateRequest struct {
 	Body io.Reader
 
-	Repository        string
-	Snapshot          string
+	Repository string
+	Snapshot   string
+
 	MasterTimeout     time.Duration
 	WaitForCompletion *bool
 
@@ -43,6 +62,8 @@ type SnapshotCreateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -91,7 +112,10 @@ func (r SnapshotCreateRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -105,6 +129,18 @@ func (r SnapshotCreateRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -186,3 +222,27 @@ func (f SnapshotCreate) WithFilterPath(v ...string) func(*SnapshotCreateRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotCreate) WithHeader(h map[string]string) func(*SnapshotCreateRequest) {
+	return func(r *SnapshotCreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotCreate) WithOpaqueID(s string) func(*SnapshotCreateRequest) {
+	return func(r *SnapshotCreateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.create_repository.go b/esapi/api.snapshot.create_repository.go
old mode 100755
new mode 100644
index 9ebf374aef..6e0dbacaa3
--- a/esapi/api.snapshot.create_repository.go
+++ b/esapi/api.snapshot.create_repository.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,16 +42,17 @@ func newSnapshotCreateRepositoryFunc(t Transport) SnapshotCreateRepository {
 
 // SnapshotCreateRepository creates a repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotCreateRepository func(repository string, body io.Reader, o ...func(*SnapshotCreateRepositoryRequest)) (*Response, error)
 
-// SnapshotCreateRepositoryRequest configures the Snapshot  Create Repository API request.
+// SnapshotCreateRepositoryRequest configures the Snapshot Create Repository API request.
 //
 type SnapshotCreateRepositoryRequest struct {
 	Body io.Reader
 
-	Repository    string
+	Repository string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 	Verify        *bool
@@ -43,6 +62,8 @@ type SnapshotCreateRepositoryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -93,7 +114,10 @@ func (r SnapshotCreateRepositoryRequest) Do(ctx context.Context, transport Trans
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +131,18 @@ func (r SnapshotCreateRepositoryRequest) Do(ctx context.Context, transport Trans
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -188,3 +224,27 @@ func (f SnapshotCreateRepository) WithFilterPath(v ...string) func(*SnapshotCrea
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotCreateRepository) WithHeader(h map[string]string) func(*SnapshotCreateRepositoryRequest) {
+	return func(r *SnapshotCreateRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotCreateRepository) WithOpaqueID(s string) func(*SnapshotCreateRepositoryRequest) {
+	return func(r *SnapshotCreateRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.delete.go b/esapi/api.snapshot.delete.go
old mode 100755
new mode 100644
index 7e85276fae..2f5b5a7d9c
--- a/esapi/api.snapshot.delete.go
+++ b/esapi/api.snapshot.delete.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,15 +40,16 @@ func newSnapshotDeleteFunc(t Transport) SnapshotDelete {
 
 // SnapshotDelete deletes a snapshot.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotDelete func(repository string, snapshot string, o ...func(*SnapshotDeleteRequest)) (*Response, error)
 
 // SnapshotDeleteRequest configures the Snapshot Delete API request.
 //
 type SnapshotDeleteRequest struct {
-	Snapshot      string
-	Repository    string
+	Repository string
+	Snapshot   string
+
 	MasterTimeout time.Duration
 
 	Pretty     bool
@@ -38,6 +57,8 @@ type SnapshotDeleteRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -82,7 +103,10 @@ func (r SnapshotDeleteRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -92,6 +116,18 @@ func (r SnapshotDeleteRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -157,3 +193,27 @@ func (f SnapshotDelete) WithFilterPath(v ...string) func(*SnapshotDeleteRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotDelete) WithHeader(h map[string]string) func(*SnapshotDeleteRequest) {
+	return func(r *SnapshotDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotDelete) WithOpaqueID(s string) func(*SnapshotDeleteRequest) {
+	return func(r *SnapshotDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.delete_repository.go b/esapi/api.snapshot.delete_repository.go
old mode 100755
new mode 100644
index 364623bee1..d7a41034a7
--- a/esapi/api.snapshot.delete_repository.go
+++ b/esapi/api.snapshot.delete_repository.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,14 +40,15 @@ func newSnapshotDeleteRepositoryFunc(t Transport) SnapshotDeleteRepository {
 
 // SnapshotDeleteRepository deletes a repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotDeleteRepository func(repository []string, o ...func(*SnapshotDeleteRepositoryRequest)) (*Response, error)
 
-// SnapshotDeleteRepositoryRequest configures the Snapshot  Delete Repository API request.
+// SnapshotDeleteRepositoryRequest configures the Snapshot Delete Repository API request.
 //
 type SnapshotDeleteRepositoryRequest struct {
-	Repository    []string
+	Repository []string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -38,6 +57,8 @@ type SnapshotDeleteRepositoryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -84,7 +105,10 @@ func (r SnapshotDeleteRepositoryRequest) Do(ctx context.Context, transport Trans
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -94,6 +118,18 @@ func (r SnapshotDeleteRepositoryRequest) Do(ctx context.Context, transport Trans
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -167,3 +203,27 @@ func (f SnapshotDeleteRepository) WithFilterPath(v ...string) func(*SnapshotDele
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotDeleteRepository) WithHeader(h map[string]string) func(*SnapshotDeleteRepositoryRequest) {
+	return func(r *SnapshotDeleteRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotDeleteRepository) WithOpaqueID(s string) func(*SnapshotDeleteRepositoryRequest) {
+	return func(r *SnapshotDeleteRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.get.go b/esapi/api.snapshot.get.go
old mode 100755
new mode 100644
index c74573c316..9635f18aa5
--- a/esapi/api.snapshot.get.go
+++ b/esapi/api.snapshot.get.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,16 +41,19 @@ func newSnapshotGetFunc(t Transport) SnapshotGet {
 
 // SnapshotGet returns information about a snapshot.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotGet func(repository string, snapshot []string, o ...func(*SnapshotGetRequest)) (*Response, error)
 
 // SnapshotGetRequest configures the Snapshot Get API request.
 //
 type SnapshotGetRequest struct {
-	Repository        string
-	Snapshot          []string
+	Repository string
+	Snapshot   []string
+
 	IgnoreUnavailable *bool
+	IncludeRepository *bool
+	IndexDetails      *bool
 	MasterTimeout     time.Duration
 	Verbose           *bool
 
@@ -41,6 +62,8 @@ type SnapshotGetRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -69,6 +92,14 @@ func (r SnapshotGetRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
 	}
 
+	if r.IncludeRepository != nil {
+		params["include_repository"] = strconv.FormatBool(*r.IncludeRepository)
+	}
+
+	if r.IndexDetails != nil {
+		params["index_details"] = strconv.FormatBool(*r.IndexDetails)
+	}
+
 	if r.MasterTimeout != 0 {
 		params["master_timeout"] = formatDuration(r.MasterTimeout)
 	}
@@ -93,7 +124,10 @@ func (r SnapshotGetRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -103,6 +137,18 @@ func (r SnapshotGetRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -137,6 +183,22 @@ func (f SnapshotGet) WithIgnoreUnavailable(v bool) func(*SnapshotGetRequest) {
 	}
 }
 
+// WithIncludeRepository - whether to include the repository name in the snapshot info. defaults to true..
+//
+func (f SnapshotGet) WithIncludeRepository(v bool) func(*SnapshotGetRequest) {
+	return func(r *SnapshotGetRequest) {
+		r.IncludeRepository = &v
+	}
+}
+
+// WithIndexDetails - whether to include details of each index in the snapshot, if those details are available. defaults to false..
+//
+func (f SnapshotGet) WithIndexDetails(v bool) func(*SnapshotGetRequest) {
+	return func(r *SnapshotGetRequest) {
+		r.IndexDetails = &v
+	}
+}
+
 // WithMasterTimeout - explicit operation timeout for connection to master node.
 //
 func (f SnapshotGet) WithMasterTimeout(v time.Duration) func(*SnapshotGetRequest) {
@@ -184,3 +246,27 @@ func (f SnapshotGet) WithFilterPath(v ...string) func(*SnapshotGetRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotGet) WithHeader(h map[string]string) func(*SnapshotGetRequest) {
+	return func(r *SnapshotGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotGet) WithOpaqueID(s string) func(*SnapshotGetRequest) {
+	return func(r *SnapshotGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.get_repository.go b/esapi/api.snapshot.get_repository.go
old mode 100755
new mode 100644
index 62cbf5cfc9..f4d079bd6c
--- a/esapi/api.snapshot.get_repository.go
+++ b/esapi/api.snapshot.get_repository.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,15 @@ func newSnapshotGetRepositoryFunc(t Transport) SnapshotGetRepository {
 
 // SnapshotGetRepository returns information about a repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotGetRepository func(o ...func(*SnapshotGetRepositoryRequest)) (*Response, error)
 
-// SnapshotGetRepositoryRequest configures the Snapshot  Get Repository API request.
+// SnapshotGetRepositoryRequest configures the Snapshot Get Repository API request.
 //
 type SnapshotGetRepositoryRequest struct {
-	Repository    []string
+	Repository []string
+
 	Local         *bool
 	MasterTimeout time.Duration
 
@@ -39,6 +58,8 @@ type SnapshotGetRepositoryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -87,7 +108,10 @@ func (r SnapshotGetRepositoryRequest) Do(ctx context.Context, transport Transpor
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -97,6 +121,18 @@ func (r SnapshotGetRepositoryRequest) Do(ctx context.Context, transport Transpor
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -178,3 +214,27 @@ func (f SnapshotGetRepository) WithFilterPath(v ...string) func(*SnapshotGetRepo
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotGetRepository) WithHeader(h map[string]string) func(*SnapshotGetRepositoryRequest) {
+	return func(r *SnapshotGetRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotGetRepository) WithOpaqueID(s string) func(*SnapshotGetRepositoryRequest) {
+	return func(r *SnapshotGetRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.repository_analyze.go b/esapi/api.snapshot.repository_analyze.go
new file mode 100644
index 0000000000..6ce0cba84c
--- /dev/null
+++ b/esapi/api.snapshot.repository_analyze.go
@@ -0,0 +1,349 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newSnapshotRepositoryAnalyzeFunc(t Transport) SnapshotRepositoryAnalyze {
+	return func(repository string, o ...func(*SnapshotRepositoryAnalyzeRequest)) (*Response, error) {
+		var r = SnapshotRepositoryAnalyzeRequest{Repository: repository}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SnapshotRepositoryAnalyze analyzes a repository for correctness and performance
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+//
+type SnapshotRepositoryAnalyze func(repository string, o ...func(*SnapshotRepositoryAnalyzeRequest)) (*Response, error)
+
+// SnapshotRepositoryAnalyzeRequest configures the Snapshot Repository Analyze API request.
+//
+type SnapshotRepositoryAnalyzeRequest struct {
+	Repository string
+
+	BlobCount             *int
+	Concurrency           *int
+	Detailed              *bool
+	EarlyReadNodeCount    *int
+	MaxBlobSize           string
+	MaxTotalDataSize      string
+	RareActionProbability *int
+	RarelyAbortWrites     *bool
+	ReadNodeCount         *int
+	Seed                  *int
+	Timeout               time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SnapshotRepositoryAnalyzeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_snapshot") + 1 + len(r.Repository) + 1 + len("_analyze"))
+	path.WriteString("/")
+	path.WriteString("_snapshot")
+	path.WriteString("/")
+	path.WriteString(r.Repository)
+	path.WriteString("/")
+	path.WriteString("_analyze")
+
+	params = make(map[string]string)
+
+	if r.BlobCount != nil {
+		params["blob_count"] = strconv.FormatInt(int64(*r.BlobCount), 10)
+	}
+
+	if r.Concurrency != nil {
+		params["concurrency"] = strconv.FormatInt(int64(*r.Concurrency), 10)
+	}
+
+	if r.Detailed != nil {
+		params["detailed"] = strconv.FormatBool(*r.Detailed)
+	}
+
+	if r.EarlyReadNodeCount != nil {
+		params["early_read_node_count"] = strconv.FormatInt(int64(*r.EarlyReadNodeCount), 10)
+	}
+
+	if r.MaxBlobSize != "" {
+		params["max_blob_size"] = r.MaxBlobSize
+	}
+
+	if r.MaxTotalDataSize != "" {
+		params["max_total_data_size"] = r.MaxTotalDataSize
+	}
+
+	if r.RareActionProbability != nil {
+		params["rare_action_probability"] = strconv.FormatInt(int64(*r.RareActionProbability), 10)
+	}
+
+	if r.RarelyAbortWrites != nil {
+		params["rarely_abort_writes"] = strconv.FormatBool(*r.RarelyAbortWrites)
+	}
+
+	if r.ReadNodeCount != nil {
+		params["read_node_count"] = strconv.FormatInt(int64(*r.ReadNodeCount), 10)
+	}
+
+	if r.Seed != nil {
+		params["seed"] = strconv.FormatInt(int64(*r.Seed), 10)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SnapshotRepositoryAnalyze) WithContext(v context.Context) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBlobCount - number of blobs to create during the test. defaults to 100..
+//
+func (f SnapshotRepositoryAnalyze) WithBlobCount(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.BlobCount = &v
+	}
+}
+
+// WithConcurrency - number of operations to run concurrently during the test. defaults to 10..
+//
+func (f SnapshotRepositoryAnalyze) WithConcurrency(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Concurrency = &v
+	}
+}
+
+// WithDetailed - whether to return detailed results or a summary. defaults to 'false' so that only the summary is returned..
+//
+func (f SnapshotRepositoryAnalyze) WithDetailed(v bool) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Detailed = &v
+	}
+}
+
+// WithEarlyReadNodeCount - number of nodes on which to perform an early read on a blob, i.e. before writing has completed. early reads are rare actions so the 'rare_action_probability' parameter is also relevant. defaults to 2..
+//
+func (f SnapshotRepositoryAnalyze) WithEarlyReadNodeCount(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.EarlyReadNodeCount = &v
+	}
+}
+
+// WithMaxBlobSize - maximum size of a blob to create during the test, e.g '1gb' or '100mb'. defaults to '10mb'..
+//
+func (f SnapshotRepositoryAnalyze) WithMaxBlobSize(v string) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.MaxBlobSize = v
+	}
+}
+
+// WithMaxTotalDataSize - maximum total size of all blobs to create during the test, e.g '1tb' or '100gb'. defaults to '1gb'..
+//
+func (f SnapshotRepositoryAnalyze) WithMaxTotalDataSize(v string) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.MaxTotalDataSize = v
+	}
+}
+
+// WithRareActionProbability - probability of taking a rare action such as an early read or an overwrite. defaults to 0.02..
+//
+func (f SnapshotRepositoryAnalyze) WithRareActionProbability(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.RareActionProbability = &v
+	}
+}
+
+// WithRarelyAbortWrites - whether to rarely abort writes before they complete. defaults to 'true'..
+//
+func (f SnapshotRepositoryAnalyze) WithRarelyAbortWrites(v bool) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.RarelyAbortWrites = &v
+	}
+}
+
+// WithReadNodeCount - number of nodes on which to read a blob after writing. defaults to 10..
+//
+func (f SnapshotRepositoryAnalyze) WithReadNodeCount(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.ReadNodeCount = &v
+	}
+}
+
+// WithSeed - seed for the random number generator used to create the test workload. defaults to a random value..
+//
+func (f SnapshotRepositoryAnalyze) WithSeed(v int) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Seed = &v
+	}
+}
+
+// WithTimeout - explicit operation timeout. defaults to '30s'..
+//
+func (f SnapshotRepositoryAnalyze) WithTimeout(v time.Duration) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SnapshotRepositoryAnalyze) WithPretty() func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SnapshotRepositoryAnalyze) WithHuman() func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SnapshotRepositoryAnalyze) WithErrorTrace() func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SnapshotRepositoryAnalyze) WithFilterPath(v ...string) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotRepositoryAnalyze) WithHeader(h map[string]string) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotRepositoryAnalyze) WithOpaqueID(s string) func(*SnapshotRepositoryAnalyzeRequest) {
+	return func(r *SnapshotRepositoryAnalyzeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.restore.go b/esapi/api.snapshot.restore.go
old mode 100755
new mode 100644
index 73870d2441..ca038e29f5
--- a/esapi/api.snapshot.restore.go
+++ b/esapi/api.snapshot.restore.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newSnapshotRestoreFunc(t Transport) SnapshotRestore {
 
 // SnapshotRestore restores a snapshot.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotRestore func(repository string, snapshot string, o ...func(*SnapshotRestoreRequest)) (*Response, error)
 
@@ -33,8 +51,9 @@ type SnapshotRestore func(repository string, snapshot string, o ...func(*Snapsho
 type SnapshotRestoreRequest struct {
 	Body io.Reader
 
-	Repository        string
-	Snapshot          string
+	Repository string
+	Snapshot   string
+
 	MasterTimeout     time.Duration
 	WaitForCompletion *bool
 
@@ -43,6 +62,8 @@ type SnapshotRestoreRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -93,7 +114,10 @@ func (r SnapshotRestoreRequest) Do(ctx context.Context, transport Transport) (*R
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -107,6 +131,18 @@ func (r SnapshotRestoreRequest) Do(ctx context.Context, transport Transport) (*R
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -188,3 +224,27 @@ func (f SnapshotRestore) WithFilterPath(v ...string) func(*SnapshotRestoreReques
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotRestore) WithHeader(h map[string]string) func(*SnapshotRestoreRequest) {
+	return func(r *SnapshotRestoreRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotRestore) WithOpaqueID(s string) func(*SnapshotRestoreRequest) {
+	return func(r *SnapshotRestoreRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.status.go b/esapi/api.snapshot.status.go
old mode 100755
new mode 100644
index 0c3cff43ff..5c6a5c4db0
--- a/esapi/api.snapshot.status.go
+++ b/esapi/api.snapshot.status.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,15 +41,16 @@ func newSnapshotStatusFunc(t Transport) SnapshotStatus {
 
 // SnapshotStatus returns information about the status of a snapshot.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotStatus func(o ...func(*SnapshotStatusRequest)) (*Response, error)
 
 // SnapshotStatusRequest configures the Snapshot Status API request.
 //
 type SnapshotStatusRequest struct {
-	Repository        string
-	Snapshot          []string
+	Repository string
+	Snapshot   []string
+
 	IgnoreUnavailable *bool
 	MasterTimeout     time.Duration
 
@@ -40,6 +59,8 @@ type SnapshotStatusRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -94,7 +115,10 @@ func (r SnapshotStatusRequest) Do(ctx context.Context, transport Transport) (*Re
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -104,6 +128,18 @@ func (r SnapshotStatusRequest) Do(ctx context.Context, transport Transport) (*Re
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -193,3 +229,27 @@ func (f SnapshotStatus) WithFilterPath(v ...string) func(*SnapshotStatusRequest)
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotStatus) WithHeader(h map[string]string) func(*SnapshotStatusRequest) {
+	return func(r *SnapshotStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotStatus) WithOpaqueID(s string) func(*SnapshotStatusRequest) {
+	return func(r *SnapshotStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.snapshot.verify_repository.go b/esapi/api.snapshot.verify_repository.go
old mode 100755
new mode 100644
index 1623866ed8..435a9f9742
--- a/esapi/api.snapshot.verify_repository.go
+++ b/esapi/api.snapshot.verify_repository.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strings"
 	"time"
 )
@@ -22,14 +40,15 @@ func newSnapshotVerifyRepositoryFunc(t Transport) SnapshotVerifyRepository {
 
 // SnapshotVerifyRepository verifies a repository.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html.
 //
 type SnapshotVerifyRepository func(repository string, o ...func(*SnapshotVerifyRepositoryRequest)) (*Response, error)
 
-// SnapshotVerifyRepositoryRequest configures the Snapshot  Verify Repository API request.
+// SnapshotVerifyRepositoryRequest configures the Snapshot Verify Repository API request.
 //
 type SnapshotVerifyRepositoryRequest struct {
-	Repository    string
+	Repository string
+
 	MasterTimeout time.Duration
 	Timeout       time.Duration
 
@@ -38,6 +57,8 @@ type SnapshotVerifyRepositoryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -86,7 +107,10 @@ func (r SnapshotVerifyRepositoryRequest) Do(ctx context.Context, transport Trans
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -96,6 +120,18 @@ func (r SnapshotVerifyRepositoryRequest) Do(ctx context.Context, transport Trans
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -169,3 +205,27 @@ func (f SnapshotVerifyRepository) WithFilterPath(v ...string) func(*SnapshotVeri
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SnapshotVerifyRepository) WithHeader(h map[string]string) func(*SnapshotVerifyRepositoryRequest) {
+	return func(r *SnapshotVerifyRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SnapshotVerifyRepository) WithOpaqueID(s string) func(*SnapshotVerifyRepositoryRequest) {
+	return func(r *SnapshotVerifyRepositoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.tasks.cancel.go b/esapi/api.tasks.cancel.go
old mode 100755
new mode 100644
index f1a256b720..8c2e7b2431
--- a/esapi/api.tasks.cancel.go
+++ b/esapi/api.tasks.cancel.go
@@ -1,9 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
+	"strconv"
 	"strings"
 )
 
@@ -21,23 +40,29 @@ func newTasksCancelFunc(t Transport) TasksCancel {
 
 // TasksCancel cancels a task, if it can be cancelled through an API.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
 //
 type TasksCancel func(o ...func(*TasksCancelRequest)) (*Response, error)
 
 // TasksCancelRequest configures the Tasks Cancel API request.
 //
 type TasksCancelRequest struct {
-	TaskID       string
-	Actions      []string
-	Nodes        []string
-	ParentTaskID string
+	TaskID string
+
+	Actions           []string
+	Nodes             []string
+	ParentTaskID      string
+	WaitForCompletion *bool
 
 	Pretty     bool
 	Human      bool
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -76,6 +101,10 @@ func (r TasksCancelRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["parent_task_id"] = r.ParentTaskID
 	}
 
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
 	if r.Pretty {
 		params["pretty"] = "true"
 	}
@@ -92,7 +121,10 @@ func (r TasksCancelRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -102,6 +134,18 @@ func (r TasksCancelRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -160,6 +204,14 @@ func (f TasksCancel) WithParentTaskID(v string) func(*TasksCancelRequest) {
 	}
 }
 
+// WithWaitForCompletion - should the request block until the cancellation of the task and its descendant tasks is completed. defaults to false.
+//
+func (f TasksCancel) WithWaitForCompletion(v bool) func(*TasksCancelRequest) {
+	return func(r *TasksCancelRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
 // WithPretty makes the response body pretty-printed.
 //
 func (f TasksCancel) WithPretty() func(*TasksCancelRequest) {
@@ -191,3 +243,27 @@ func (f TasksCancel) WithFilterPath(v ...string) func(*TasksCancelRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TasksCancel) WithHeader(h map[string]string) func(*TasksCancelRequest) {
+	return func(r *TasksCancelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TasksCancel) WithOpaqueID(s string) func(*TasksCancelRequest) {
+	return func(r *TasksCancelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.tasks.get.go b/esapi/api.tasks.get.go
old mode 100755
new mode 100644
index c2d71756c4..d8d4308ed1
--- a/esapi/api.tasks.get.go
+++ b/esapi/api.tasks.get.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,14 +41,17 @@ func newTasksGetFunc(t Transport) TasksGet {
 
 // TasksGet returns information about a task.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
 //
 type TasksGet func(task_id string, o ...func(*TasksGetRequest)) (*Response, error)
 
 // TasksGetRequest configures the Tasks Get API request.
 //
 type TasksGetRequest struct {
-	TaskID            string
+	TaskID string
+
 	Timeout           time.Duration
 	WaitForCompletion *bool
 
@@ -39,6 +60,8 @@ type TasksGetRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -85,7 +108,10 @@ func (r TasksGetRequest) Do(ctx context.Context, transport Transport) (*Response
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -95,6 +121,18 @@ func (r TasksGetRequest) Do(ctx context.Context, transport Transport) (*Response
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -168,3 +206,27 @@ func (f TasksGet) WithFilterPath(v ...string) func(*TasksGetRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TasksGet) WithHeader(h map[string]string) func(*TasksGetRequest) {
+	return func(r *TasksGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TasksGet) WithOpaqueID(s string) func(*TasksGetRequest) {
+	return func(r *TasksGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.tasks.list.go b/esapi/api.tasks.list.go
old mode 100755
new mode 100644
index 9e9371fa01..3a498b4ff6
--- a/esapi/api.tasks.list.go
+++ b/esapi/api.tasks.list.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -23,7 +41,9 @@ func newTasksListFunc(t Transport) TasksList {
 
 // TasksList returns a list of tasks.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html.
 //
 type TasksList func(o ...func(*TasksListRequest)) (*Response, error)
 
@@ -43,6 +63,8 @@ type TasksListRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -106,7 +128,10 @@ func (r TasksListRequest) Do(ctx context.Context, transport Transport) (*Respons
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -116,6 +141,18 @@ func (r TasksListRequest) Do(ctx context.Context, transport Transport) (*Respons
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -229,3 +266,27 @@ func (f TasksList) WithFilterPath(v ...string) func(*TasksListRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TasksList) WithHeader(h map[string]string) func(*TasksListRequest) {
+	return func(r *TasksListRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TasksList) WithOpaqueID(s string) func(*TasksListRequest) {
+	return func(r *TasksListRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.terms_enum.go b/esapi/api.terms_enum.go
new file mode 100644
index 0000000000..2e909a1d73
--- /dev/null
+++ b/esapi/api.terms_enum.go
@@ -0,0 +1,216 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newTermsEnumFunc(t Transport) TermsEnum {
+	return func(index []string, o ...func(*TermsEnumRequest)) (*Response, error) {
+		var r = TermsEnumRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TermsEnum the terms enum API  can be used to discover terms in the index that begin with the provided string. It is designed for low-latency look-ups used in auto-complete scenarios.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/search-terms-enum.html.
+//
+type TermsEnum func(index []string, o ...func(*TermsEnumRequest)) (*Response, error)
+
+// TermsEnumRequest configures the Terms Enum API request.
+//
+type TermsEnumRequest struct {
+	Index []string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TermsEnumRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_terms_enum"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_terms_enum")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TermsEnum) WithContext(v context.Context) func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - field name, string which is the prefix expected in matching terms, timeout and size for max number of results.
+//
+func (f TermsEnum) WithBody(v io.Reader) func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TermsEnum) WithPretty() func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TermsEnum) WithHuman() func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TermsEnum) WithErrorTrace() func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TermsEnum) WithFilterPath(v ...string) func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TermsEnum) WithHeader(h map[string]string) func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TermsEnum) WithOpaqueID(s string) func(*TermsEnumRequest) {
+	return func(r *TermsEnumRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.termvectors.go b/esapi/api.termvectors.go
old mode 100755
new mode 100644
index 51b3d1fe0a..b3b4c276d2
--- a/esapi/api.termvectors.go
+++ b/esapi/api.termvectors.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -23,7 +41,7 @@ func newTermvectorsFunc(t Transport) Termvectors {
 
 // Termvectors returns information and statistics about terms in the fields of a particular document.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-termvectors.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-termvectors.html.
 //
 type Termvectors func(index string, o ...func(*TermvectorsRequest)) (*Response, error)
 
@@ -33,12 +51,12 @@ type TermvectorsRequest struct {
 	Index        string
 	DocumentType string
 	DocumentID   string
-	Body         io.Reader
+
+	Body io.Reader
 
 	Fields          []string
 	FieldStatistics *bool
 	Offsets         *bool
-	Parent          string
 	Payloads        *bool
 	Positions       *bool
 	Preference      string
@@ -53,6 +71,8 @@ type TermvectorsRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -65,7 +85,7 @@ func (r TermvectorsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params map[string]string
 	)
 
-	method = "GET"
+	method = "POST"
 
 	if r.DocumentType == "" {
 		r.DocumentType = "_doc"
@@ -99,10 +119,6 @@ func (r TermvectorsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["offsets"] = strconv.FormatBool(*r.Offsets)
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Payloads != nil {
 		params["payloads"] = strconv.FormatBool(*r.Payloads)
 	}
@@ -151,7 +167,10 @@ func (r TermvectorsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -165,6 +184,18 @@ func (r TermvectorsRequest) Do(ctx context.Context, transport Transport) (*Respo
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -191,6 +222,14 @@ func (f Termvectors) WithContext(v context.Context) func(*TermvectorsRequest) {
 	}
 }
 
+// WithBody - Define parameters and or supply a document to get termvectors for. See documentation..
+//
+func (f Termvectors) WithBody(v io.Reader) func(*TermvectorsRequest) {
+	return func(r *TermvectorsRequest) {
+		r.Body = v
+	}
+}
+
 // WithDocumentID - the ID of the document, when not specified a doc param should be supplied..
 //
 func (f Termvectors) WithDocumentID(v string) func(*TermvectorsRequest) {
@@ -207,14 +246,6 @@ func (f Termvectors) WithDocumentType(v string) func(*TermvectorsRequest) {
 	}
 }
 
-// WithBody - Define parameters and or supply a document to get termvectors for. See documentation..
-//
-func (f Termvectors) WithBody(v io.Reader) func(*TermvectorsRequest) {
-	return func(r *TermvectorsRequest) {
-		r.Body = v
-	}
-}
-
 // WithFields - a list of fields to return..
 //
 func (f Termvectors) WithFields(v ...string) func(*TermvectorsRequest) {
@@ -239,14 +270,6 @@ func (f Termvectors) WithOffsets(v bool) func(*TermvectorsRequest) {
 	}
 }
 
-// WithParent - parent ID of documents..
-//
-func (f Termvectors) WithParent(v string) func(*TermvectorsRequest) {
-	return func(r *TermvectorsRequest) {
-		r.Parent = v
-	}
-}
-
 // WithPayloads - specifies if term payloads should be returned..
 //
 func (f Termvectors) WithPayloads(v bool) func(*TermvectorsRequest) {
@@ -342,3 +365,27 @@ func (f Termvectors) WithFilterPath(v ...string) func(*TermvectorsRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Termvectors) WithHeader(h map[string]string) func(*TermvectorsRequest) {
+	return func(r *TermvectorsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Termvectors) WithOpaqueID(s string) func(*TermvectorsRequest) {
+	return func(r *TermvectorsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.update.go b/esapi/api.update.go
old mode 100755
new mode 100644
index 57441f0bad..4e36508743
--- a/esapi/api.update.go
+++ b/esapi/api.update.go
@@ -1,10 +1,28 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -24,7 +42,7 @@ func newUpdateFunc(t Transport) Update {
 
 // Update updates a document with a script or partial document.
 //
-// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/master/docs-update.html.
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-update.html.
 //
 type Update func(index string, id string, body io.Reader, o ...func(*UpdateRequest)) (*Response, error)
 
@@ -34,13 +52,14 @@ type UpdateRequest struct {
 	Index        string
 	DocumentType string
 	DocumentID   string
-	Body         io.Reader
+
+	Body io.Reader
 
 	IfPrimaryTerm       *int
 	IfSeqNo             *int
 	Lang                string
-	Parent              string
 	Refresh             string
+	RequireAlias        *bool
 	RetryOnConflict     *int
 	Routing             string
 	Source              []string
@@ -54,6 +73,8 @@ type UpdateRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -98,14 +119,14 @@ func (r UpdateRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["lang"] = r.Lang
 	}
 
-	if r.Parent != "" {
-		params["parent"] = r.Parent
-	}
-
 	if r.Refresh != "" {
 		params["refresh"] = r.Refresh
 	}
 
+	if r.RequireAlias != nil {
+		params["require_alias"] = strconv.FormatBool(*r.RequireAlias)
+	}
+
 	if r.RetryOnConflict != nil {
 		params["retry_on_conflict"] = strconv.FormatInt(int64(*r.RetryOnConflict), 10)
 	}
@@ -150,7 +171,10 @@ func (r UpdateRequest) Do(ctx context.Context, transport Transport) (*Response,
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -164,6 +188,18 @@ func (r UpdateRequest) Do(ctx context.Context, transport Transport) (*Response,
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -222,19 +258,19 @@ func (f Update) WithLang(v string) func(*UpdateRequest) {
 	}
 }
 
-// WithParent - ID of the parent document. is is only used for routing and when for the upsert request.
+// WithRefresh - if `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
 //
-func (f Update) WithParent(v string) func(*UpdateRequest) {
+func (f Update) WithRefresh(v string) func(*UpdateRequest) {
 	return func(r *UpdateRequest) {
-		r.Parent = v
+		r.Refresh = v
 	}
 }
 
-// WithRefresh - if `true` then refresh the effected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes..
+// WithRequireAlias - when true, requires destination is an alias. default is false.
 //
-func (f Update) WithRefresh(v string) func(*UpdateRequest) {
+func (f Update) WithRequireAlias(v bool) func(*UpdateRequest) {
 	return func(r *UpdateRequest) {
-		r.Refresh = v
+		r.RequireAlias = &v
 	}
 }
 
@@ -325,3 +361,27 @@ func (f Update) WithFilterPath(v ...string) func(*UpdateRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f Update) WithHeader(h map[string]string) func(*UpdateRequest) {
+	return func(r *UpdateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f Update) WithOpaqueID(s string) func(*UpdateRequest) {
+	return func(r *UpdateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.update_by_query.go b/esapi/api.update_by_query.go
old mode 100755
new mode 100644
index e3952e6575..2bda821c34
--- a/esapi/api.update_by_query.go
+++ b/esapi/api.update_by_query.go
@@ -1,10 +1,29 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"fmt"
 	"io"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -34,7 +53,8 @@ type UpdateByQuery func(index []string, o ...func(*UpdateByQueryRequest)) (*Resp
 type UpdateByQueryRequest struct {
 	Index        []string
 	DocumentType []string
-	Body         io.Reader
+
+	Body io.Reader
 
 	AllowNoIndices      *bool
 	Analyzer            string
@@ -46,6 +66,7 @@ type UpdateByQueryRequest struct {
 	From                *int
 	IgnoreUnavailable   *bool
 	Lenient             *bool
+	MaxDocs             *int
 	Pipeline            string
 	Preference          string
 	Query               string
@@ -58,11 +79,8 @@ type UpdateByQueryRequest struct {
 	SearchTimeout       time.Duration
 	SearchType          string
 	Size                *int
-	Slices              *int
+	Slices              interface{}
 	Sort                []string
-	Source              []string
-	SourceExcludes      []string
-	SourceIncludes      []string
 	Stats               []string
 	TerminateAfter      *int
 	Timeout             time.Duration
@@ -76,6 +94,8 @@ type UpdateByQueryRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -142,6 +162,10 @@ func (r UpdateByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["lenient"] = strconv.FormatBool(*r.Lenient)
 	}
 
+	if r.MaxDocs != nil {
+		params["max_docs"] = strconv.FormatInt(int64(*r.MaxDocs), 10)
+	}
+
 	if r.Pipeline != "" {
 		params["pipeline"] = r.Pipeline
 	}
@@ -191,25 +215,13 @@ func (r UpdateByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 	}
 
 	if r.Slices != nil {
-		params["slices"] = strconv.FormatInt(int64(*r.Slices), 10)
+		params["slices"] = fmt.Sprintf("%v", r.Slices)
 	}
 
 	if len(r.Sort) > 0 {
 		params["sort"] = strings.Join(r.Sort, ",")
 	}
 
-	if len(r.Source) > 0 {
-		params["_source"] = strings.Join(r.Source, ",")
-	}
-
-	if len(r.SourceExcludes) > 0 {
-		params["_source_excludes"] = strings.Join(r.SourceExcludes, ",")
-	}
-
-	if len(r.SourceIncludes) > 0 {
-		params["_source_includes"] = strings.Join(r.SourceIncludes, ",")
-	}
-
 	if len(r.Stats) > 0 {
 		params["stats"] = strings.Join(r.Stats, ",")
 	}
@@ -254,7 +266,10 @@ func (r UpdateByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), r.Body)
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -268,6 +283,18 @@ func (r UpdateByQueryRequest) Do(ctx context.Context, transport Transport) (*Res
 		req.Header[headerContentType] = headerContentTypeJSON
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -294,19 +321,19 @@ func (f UpdateByQuery) WithContext(v context.Context) func(*UpdateByQueryRequest
 	}
 }
 
-// WithDocumentType - a list of document types to search; leave empty to perform the operation on all types.
+// WithBody - The search definition using the Query DSL.
 //
-func (f UpdateByQuery) WithDocumentType(v ...string) func(*UpdateByQueryRequest) {
+func (f UpdateByQuery) WithBody(v io.Reader) func(*UpdateByQueryRequest) {
 	return func(r *UpdateByQueryRequest) {
-		r.DocumentType = v
+		r.Body = v
 	}
 }
 
-// WithBody - The search definition using the Query DSL.
+// WithDocumentType - a list of document types to search; leave empty to perform the operation on all types.
 //
-func (f UpdateByQuery) WithBody(v io.Reader) func(*UpdateByQueryRequest) {
+func (f UpdateByQuery) WithDocumentType(v ...string) func(*UpdateByQueryRequest) {
 	return func(r *UpdateByQueryRequest) {
-		r.Body = v
+		r.DocumentType = v
 	}
 }
 
@@ -390,6 +417,14 @@ func (f UpdateByQuery) WithLenient(v bool) func(*UpdateByQueryRequest) {
 	}
 }
 
+// WithMaxDocs - maximum number of documents to process (default: all documents).
+//
+func (f UpdateByQuery) WithMaxDocs(v int) func(*UpdateByQueryRequest) {
+	return func(r *UpdateByQueryRequest) {
+		r.MaxDocs = &v
+	}
+}
+
 // WithPipeline - ingest pipeline to set on index requests made by this action. (default: none).
 //
 func (f UpdateByQuery) WithPipeline(v string) func(*UpdateByQueryRequest) {
@@ -414,7 +449,7 @@ func (f UpdateByQuery) WithQuery(v string) func(*UpdateByQueryRequest) {
 	}
 }
 
-// WithRefresh - should the effected indexes be refreshed?.
+// WithRefresh - should the affected indexes be refreshed?.
 //
 func (f UpdateByQuery) WithRefresh(v bool) func(*UpdateByQueryRequest) {
 	return func(r *UpdateByQueryRequest) {
@@ -478,7 +513,7 @@ func (f UpdateByQuery) WithSearchType(v string) func(*UpdateByQueryRequest) {
 	}
 }
 
-// WithSize - number of hits to return (default: 10).
+// WithSize - deprecated, please use `max_docs` instead.
 //
 func (f UpdateByQuery) WithSize(v int) func(*UpdateByQueryRequest) {
 	return func(r *UpdateByQueryRequest) {
@@ -486,11 +521,11 @@ func (f UpdateByQuery) WithSize(v int) func(*UpdateByQueryRequest) {
 	}
 }
 
-// WithSlices - the number of slices this task should be divided into. defaults to 1 meaning the task isn't sliced into subtasks..
+// WithSlices - the number of slices this task should be divided into. defaults to 1, meaning the task isn't sliced into subtasks. can be set to `auto`..
 //
-func (f UpdateByQuery) WithSlices(v int) func(*UpdateByQueryRequest) {
+func (f UpdateByQuery) WithSlices(v interface{}) func(*UpdateByQueryRequest) {
 	return func(r *UpdateByQueryRequest) {
-		r.Slices = &v
+		r.Slices = v
 	}
 }
 
@@ -502,30 +537,6 @@ func (f UpdateByQuery) WithSort(v ...string) func(*UpdateByQueryRequest) {
 	}
 }
 
-// WithSource - true or false to return the _source field or not, or a list of fields to return.
-//
-func (f UpdateByQuery) WithSource(v ...string) func(*UpdateByQueryRequest) {
-	return func(r *UpdateByQueryRequest) {
-		r.Source = v
-	}
-}
-
-// WithSourceExcludes - a list of fields to exclude from the returned _source field.
-//
-func (f UpdateByQuery) WithSourceExcludes(v ...string) func(*UpdateByQueryRequest) {
-	return func(r *UpdateByQueryRequest) {
-		r.SourceExcludes = v
-	}
-}
-
-// WithSourceIncludes - a list of fields to extract and return from the _source field.
-//
-func (f UpdateByQuery) WithSourceIncludes(v ...string) func(*UpdateByQueryRequest) {
-	return func(r *UpdateByQueryRequest) {
-		r.SourceIncludes = v
-	}
-}
-
 // WithStats - specific 'tag' of the request for logging and statistical purposes.
 //
 func (f UpdateByQuery) WithStats(v ...string) func(*UpdateByQueryRequest) {
@@ -613,3 +624,27 @@ func (f UpdateByQuery) WithFilterPath(v ...string) func(*UpdateByQueryRequest) {
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f UpdateByQuery) WithHeader(h map[string]string) func(*UpdateByQueryRequest) {
+	return func(r *UpdateByQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f UpdateByQuery) WithOpaqueID(s string) func(*UpdateByQueryRequest) {
+	return func(r *UpdateByQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.update_by_query_rethrottle.go b/esapi/api.update_by_query_rethrottle.go
old mode 100755
new mode 100644
index 170db010c7..0a4e5da0f4
--- a/esapi/api.update_by_query_rethrottle.go
+++ b/esapi/api.update_by_query_rethrottle.go
@@ -1,9 +1,27 @@
-// Code generated from specification version 7.0.0: DO NOT EDIT
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
 
 package esapi
 
 import (
 	"context"
+	"net/http"
 	"strconv"
 	"strings"
 )
@@ -29,7 +47,8 @@ type UpdateByQueryRethrottle func(task_id string, requests_per_second *int, o ..
 // UpdateByQueryRethrottleRequest configures the Update By Query Rethrottle API request.
 //
 type UpdateByQueryRethrottleRequest struct {
-	TaskID            string
+	TaskID string
+
 	RequestsPerSecond *int
 
 	Pretty     bool
@@ -37,6 +56,8 @@ type UpdateByQueryRethrottleRequest struct {
 	ErrorTrace bool
 	FilterPath []string
 
+	Header http.Header
+
 	ctx context.Context
 }
 
@@ -81,7 +102,10 @@ func (r UpdateByQueryRethrottleRequest) Do(ctx context.Context, transport Transp
 		params["filter_path"] = strings.Join(r.FilterPath, ",")
 	}
 
-	req, _ := newRequest(method, path.String(), nil)
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(params) > 0 {
 		q := req.URL.Query()
@@ -91,6 +115,18 @@ func (r UpdateByQueryRethrottleRequest) Do(ctx context.Context, transport Transp
 		req.URL.RawQuery = q.Encode()
 	}
 
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
 	if ctx != nil {
 		req = req.WithContext(ctx)
 	}
@@ -156,3 +192,27 @@ func (f UpdateByQueryRethrottle) WithFilterPath(v ...string) func(*UpdateByQuery
 		r.FilterPath = v
 	}
 }
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f UpdateByQueryRethrottle) WithHeader(h map[string]string) func(*UpdateByQueryRethrottleRequest) {
+	return func(r *UpdateByQueryRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f UpdateByQueryRethrottle) WithOpaqueID(s string) func(*UpdateByQueryRethrottleRequest) {
+	return func(r *UpdateByQueryRethrottleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.async_search.delete.go b/esapi/api.xpack.async_search.delete.go
new file mode 100644
index 0000000000..72c2f6259c
--- /dev/null
+++ b/esapi/api.xpack.async_search.delete.go
@@ -0,0 +1,201 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAsyncSearchDeleteFunc(t Transport) AsyncSearchDelete {
+	return func(id string, o ...func(*AsyncSearchDeleteRequest)) (*Response, error) {
+		var r = AsyncSearchDeleteRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AsyncSearchDelete - Deletes an async search by ID. If the search is still running, the search request will be cancelled. Otherwise, the saved search results are deleted.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html.
+//
+type AsyncSearchDelete func(id string, o ...func(*AsyncSearchDeleteRequest)) (*Response, error)
+
+// AsyncSearchDeleteRequest configures the Async Search Delete API request.
+//
+type AsyncSearchDeleteRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AsyncSearchDeleteRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_async_search") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_async_search")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AsyncSearchDelete) WithContext(v context.Context) func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AsyncSearchDelete) WithPretty() func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AsyncSearchDelete) WithHuman() func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AsyncSearchDelete) WithErrorTrace() func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AsyncSearchDelete) WithFilterPath(v ...string) func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AsyncSearchDelete) WithHeader(h map[string]string) func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AsyncSearchDelete) WithOpaqueID(s string) func(*AsyncSearchDeleteRequest) {
+	return func(r *AsyncSearchDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.async_search.get.go b/esapi/api.xpack.async_search.get.go
new file mode 100644
index 0000000000..6301ef8035
--- /dev/null
+++ b/esapi/api.xpack.async_search.get.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newAsyncSearchGetFunc(t Transport) AsyncSearchGet {
+	return func(id string, o ...func(*AsyncSearchGetRequest)) (*Response, error) {
+		var r = AsyncSearchGetRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AsyncSearchGet - Retrieves the results of a previously submitted async search request given its ID.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html.
+//
+type AsyncSearchGet func(id string, o ...func(*AsyncSearchGetRequest)) (*Response, error)
+
+// AsyncSearchGetRequest configures the Async Search Get API request.
+//
+type AsyncSearchGetRequest struct {
+	DocumentID string
+
+	KeepAlive                time.Duration
+	TypedKeys                *bool
+	WaitForCompletionTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AsyncSearchGetRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_async_search") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_async_search")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.KeepAlive != 0 {
+		params["keep_alive"] = formatDuration(r.KeepAlive)
+	}
+
+	if r.TypedKeys != nil {
+		params["typed_keys"] = strconv.FormatBool(*r.TypedKeys)
+	}
+
+	if r.WaitForCompletionTimeout != 0 {
+		params["wait_for_completion_timeout"] = formatDuration(r.WaitForCompletionTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AsyncSearchGet) WithContext(v context.Context) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.ctx = v
+	}
+}
+
+// WithKeepAlive - specify the time interval in which the results (partial or final) for this search will be available.
+//
+func (f AsyncSearchGet) WithKeepAlive(v time.Duration) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithTypedKeys - specify whether aggregation and suggester names should be prefixed by their respective types in the response.
+//
+func (f AsyncSearchGet) WithTypedKeys(v bool) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.TypedKeys = &v
+	}
+}
+
+// WithWaitForCompletionTimeout - specify the time that the request should block waiting for the final response.
+//
+func (f AsyncSearchGet) WithWaitForCompletionTimeout(v time.Duration) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.WaitForCompletionTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AsyncSearchGet) WithPretty() func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AsyncSearchGet) WithHuman() func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AsyncSearchGet) WithErrorTrace() func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AsyncSearchGet) WithFilterPath(v ...string) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AsyncSearchGet) WithHeader(h map[string]string) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AsyncSearchGet) WithOpaqueID(s string) func(*AsyncSearchGetRequest) {
+	return func(r *AsyncSearchGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.async_search.status.go b/esapi/api.xpack.async_search.status.go
new file mode 100644
index 0000000000..8aceea68b8
--- /dev/null
+++ b/esapi/api.xpack.async_search.status.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAsyncSearchStatusFunc(t Transport) AsyncSearchStatus {
+	return func(id string, o ...func(*AsyncSearchStatusRequest)) (*Response, error) {
+		var r = AsyncSearchStatusRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AsyncSearchStatus - Retrieves the status of a previously submitted async search request given its ID.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html.
+//
+type AsyncSearchStatus func(id string, o ...func(*AsyncSearchStatusRequest)) (*Response, error)
+
+// AsyncSearchStatusRequest configures the Async Search Status API request.
+//
+type AsyncSearchStatusRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AsyncSearchStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_async_search") + 1 + len("status") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_async_search")
+	path.WriteString("/")
+	path.WriteString("status")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AsyncSearchStatus) WithContext(v context.Context) func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AsyncSearchStatus) WithPretty() func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AsyncSearchStatus) WithHuman() func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AsyncSearchStatus) WithErrorTrace() func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AsyncSearchStatus) WithFilterPath(v ...string) func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AsyncSearchStatus) WithHeader(h map[string]string) func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AsyncSearchStatus) WithOpaqueID(s string) func(*AsyncSearchStatusRequest) {
+	return func(r *AsyncSearchStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.async_search.submit.go b/esapi/api.xpack.async_search.submit.go
new file mode 100644
index 0000000000..e0ca0d34cc
--- /dev/null
+++ b/esapi/api.xpack.async_search.submit.go
@@ -0,0 +1,762 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newAsyncSearchSubmitFunc(t Transport) AsyncSearchSubmit {
+	return func(o ...func(*AsyncSearchSubmitRequest)) (*Response, error) {
+		var r = AsyncSearchSubmitRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AsyncSearchSubmit - Executes a search request asynchronously.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html.
+//
+type AsyncSearchSubmit func(o ...func(*AsyncSearchSubmitRequest)) (*Response, error)
+
+// AsyncSearchSubmitRequest configures the Async Search Submit API request.
+//
+type AsyncSearchSubmitRequest struct {
+	Index []string
+
+	Body io.Reader
+
+	AllowNoIndices             *bool
+	AllowPartialSearchResults  *bool
+	Analyzer                   string
+	AnalyzeWildcard            *bool
+	BatchedReduceSize          *int
+	DefaultOperator            string
+	Df                         string
+	DocvalueFields             []string
+	ExpandWildcards            string
+	Explain                    *bool
+	From                       *int
+	IgnoreThrottled            *bool
+	IgnoreUnavailable          *bool
+	KeepAlive                  time.Duration
+	KeepOnCompletion           *bool
+	Lenient                    *bool
+	MaxConcurrentShardRequests *int
+	Preference                 string
+	Query                      string
+	RequestCache               *bool
+	Routing                    []string
+	SearchType                 string
+	SeqNoPrimaryTerm           *bool
+	Size                       *int
+	Sort                       []string
+	Source                     []string
+	SourceExcludes             []string
+	SourceIncludes             []string
+	Stats                      []string
+	StoredFields               []string
+	SuggestField               string
+	SuggestMode                string
+	SuggestSize                *int
+	SuggestText                string
+	TerminateAfter             *int
+	Timeout                    time.Duration
+	TrackScores                *bool
+	TrackTotalHits             *bool
+	TypedKeys                  *bool
+	Version                    *bool
+	WaitForCompletionTimeout   time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AsyncSearchSubmitRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_async_search"))
+	if len(r.Index) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Index, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("_async_search")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.AllowPartialSearchResults != nil {
+		params["allow_partial_search_results"] = strconv.FormatBool(*r.AllowPartialSearchResults)
+	}
+
+	if r.Analyzer != "" {
+		params["analyzer"] = r.Analyzer
+	}
+
+	if r.AnalyzeWildcard != nil {
+		params["analyze_wildcard"] = strconv.FormatBool(*r.AnalyzeWildcard)
+	}
+
+	if r.BatchedReduceSize != nil {
+		params["batched_reduce_size"] = strconv.FormatInt(int64(*r.BatchedReduceSize), 10)
+	}
+
+	if r.DefaultOperator != "" {
+		params["default_operator"] = r.DefaultOperator
+	}
+
+	if r.Df != "" {
+		params["df"] = r.Df
+	}
+
+	if len(r.DocvalueFields) > 0 {
+		params["docvalue_fields"] = strings.Join(r.DocvalueFields, ",")
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.Explain != nil {
+		params["explain"] = strconv.FormatBool(*r.Explain)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.IgnoreThrottled != nil {
+		params["ignore_throttled"] = strconv.FormatBool(*r.IgnoreThrottled)
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.KeepAlive != 0 {
+		params["keep_alive"] = formatDuration(r.KeepAlive)
+	}
+
+	if r.KeepOnCompletion != nil {
+		params["keep_on_completion"] = strconv.FormatBool(*r.KeepOnCompletion)
+	}
+
+	if r.Lenient != nil {
+		params["lenient"] = strconv.FormatBool(*r.Lenient)
+	}
+
+	if r.MaxConcurrentShardRequests != nil {
+		params["max_concurrent_shard_requests"] = strconv.FormatInt(int64(*r.MaxConcurrentShardRequests), 10)
+	}
+
+	if r.Preference != "" {
+		params["preference"] = r.Preference
+	}
+
+	if r.Query != "" {
+		params["q"] = r.Query
+	}
+
+	if r.RequestCache != nil {
+		params["request_cache"] = strconv.FormatBool(*r.RequestCache)
+	}
+
+	if len(r.Routing) > 0 {
+		params["routing"] = strings.Join(r.Routing, ",")
+	}
+
+	if r.SearchType != "" {
+		params["search_type"] = r.SearchType
+	}
+
+	if r.SeqNoPrimaryTerm != nil {
+		params["seq_no_primary_term"] = strconv.FormatBool(*r.SeqNoPrimaryTerm)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if len(r.Sort) > 0 {
+		params["sort"] = strings.Join(r.Sort, ",")
+	}
+
+	if len(r.Source) > 0 {
+		params["_source"] = strings.Join(r.Source, ",")
+	}
+
+	if len(r.SourceExcludes) > 0 {
+		params["_source_excludes"] = strings.Join(r.SourceExcludes, ",")
+	}
+
+	if len(r.SourceIncludes) > 0 {
+		params["_source_includes"] = strings.Join(r.SourceIncludes, ",")
+	}
+
+	if len(r.Stats) > 0 {
+		params["stats"] = strings.Join(r.Stats, ",")
+	}
+
+	if len(r.StoredFields) > 0 {
+		params["stored_fields"] = strings.Join(r.StoredFields, ",")
+	}
+
+	if r.SuggestField != "" {
+		params["suggest_field"] = r.SuggestField
+	}
+
+	if r.SuggestMode != "" {
+		params["suggest_mode"] = r.SuggestMode
+	}
+
+	if r.SuggestSize != nil {
+		params["suggest_size"] = strconv.FormatInt(int64(*r.SuggestSize), 10)
+	}
+
+	if r.SuggestText != "" {
+		params["suggest_text"] = r.SuggestText
+	}
+
+	if r.TerminateAfter != nil {
+		params["terminate_after"] = strconv.FormatInt(int64(*r.TerminateAfter), 10)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.TrackScores != nil {
+		params["track_scores"] = strconv.FormatBool(*r.TrackScores)
+	}
+
+	if r.TrackTotalHits != nil {
+		params["track_total_hits"] = strconv.FormatBool(*r.TrackTotalHits)
+	}
+
+	if r.TypedKeys != nil {
+		params["typed_keys"] = strconv.FormatBool(*r.TypedKeys)
+	}
+
+	if r.Version != nil {
+		params["version"] = strconv.FormatBool(*r.Version)
+	}
+
+	if r.WaitForCompletionTimeout != 0 {
+		params["wait_for_completion_timeout"] = formatDuration(r.WaitForCompletionTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AsyncSearchSubmit) WithContext(v context.Context) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The search definition using the Query DSL.
+//
+func (f AsyncSearchSubmit) WithBody(v io.Reader) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Body = v
+	}
+}
+
+// WithIndex - a list of index names to search; use _all to perform the operation on all indices.
+//
+func (f AsyncSearchSubmit) WithIndex(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Index = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f AsyncSearchSubmit) WithAllowNoIndices(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithAllowPartialSearchResults - indicate if an error should be returned if there is a partial search failure or timeout.
+//
+func (f AsyncSearchSubmit) WithAllowPartialSearchResults(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.AllowPartialSearchResults = &v
+	}
+}
+
+// WithAnalyzer - the analyzer to use for the query string.
+//
+func (f AsyncSearchSubmit) WithAnalyzer(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Analyzer = v
+	}
+}
+
+// WithAnalyzeWildcard - specify whether wildcard and prefix queries should be analyzed (default: false).
+//
+func (f AsyncSearchSubmit) WithAnalyzeWildcard(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.AnalyzeWildcard = &v
+	}
+}
+
+// WithBatchedReduceSize - the number of shard results that should be reduced at once on the coordinating node. this value should be used as the granularity at which progress results will be made available..
+//
+func (f AsyncSearchSubmit) WithBatchedReduceSize(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.BatchedReduceSize = &v
+	}
+}
+
+// WithDefaultOperator - the default operator for query string query (and or or).
+//
+func (f AsyncSearchSubmit) WithDefaultOperator(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.DefaultOperator = v
+	}
+}
+
+// WithDf - the field to use as default where no field prefix is given in the query string.
+//
+func (f AsyncSearchSubmit) WithDf(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Df = v
+	}
+}
+
+// WithDocvalueFields - a list of fields to return as the docvalue representation of a field for each hit.
+//
+func (f AsyncSearchSubmit) WithDocvalueFields(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.DocvalueFields = v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f AsyncSearchSubmit) WithExpandWildcards(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithExplain - specify whether to return detailed information about score computation as part of a hit.
+//
+func (f AsyncSearchSubmit) WithExplain(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Explain = &v
+	}
+}
+
+// WithFrom - starting offset (default: 0).
+//
+func (f AsyncSearchSubmit) WithFrom(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.From = &v
+	}
+}
+
+// WithIgnoreThrottled - whether specified concrete, expanded or aliased indices should be ignored when throttled.
+//
+func (f AsyncSearchSubmit) WithIgnoreThrottled(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.IgnoreThrottled = &v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f AsyncSearchSubmit) WithIgnoreUnavailable(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithKeepAlive - update the time interval in which the results (partial or final) for this search will be available.
+//
+func (f AsyncSearchSubmit) WithKeepAlive(v time.Duration) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithKeepOnCompletion - control whether the response should be stored in the cluster if it completed within the provided [wait_for_completion] time (default: false).
+//
+func (f AsyncSearchSubmit) WithKeepOnCompletion(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.KeepOnCompletion = &v
+	}
+}
+
+// WithLenient - specify whether format-based query failures (such as providing text to a numeric field) should be ignored.
+//
+func (f AsyncSearchSubmit) WithLenient(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Lenient = &v
+	}
+}
+
+// WithMaxConcurrentShardRequests - the number of concurrent shard requests per node this search executes concurrently. this value should be used to limit the impact of the search on the cluster in order to limit the number of concurrent shard requests.
+//
+func (f AsyncSearchSubmit) WithMaxConcurrentShardRequests(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.MaxConcurrentShardRequests = &v
+	}
+}
+
+// WithPreference - specify the node or shard the operation should be performed on (default: random).
+//
+func (f AsyncSearchSubmit) WithPreference(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Preference = v
+	}
+}
+
+// WithQuery - query in the lucene query string syntax.
+//
+func (f AsyncSearchSubmit) WithQuery(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Query = v
+	}
+}
+
+// WithRequestCache - specify if request cache should be used for this request or not, defaults to true.
+//
+func (f AsyncSearchSubmit) WithRequestCache(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.RequestCache = &v
+	}
+}
+
+// WithRouting - a list of specific routing values.
+//
+func (f AsyncSearchSubmit) WithRouting(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Routing = v
+	}
+}
+
+// WithSearchType - search operation type.
+//
+func (f AsyncSearchSubmit) WithSearchType(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SearchType = v
+	}
+}
+
+// WithSeqNoPrimaryTerm - specify whether to return sequence number and primary term of the last modification of each hit.
+//
+func (f AsyncSearchSubmit) WithSeqNoPrimaryTerm(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SeqNoPrimaryTerm = &v
+	}
+}
+
+// WithSize - number of hits to return (default: 10).
+//
+func (f AsyncSearchSubmit) WithSize(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Size = &v
+	}
+}
+
+// WithSort - a list of <field>:<direction> pairs.
+//
+func (f AsyncSearchSubmit) WithSort(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Sort = v
+	}
+}
+
+// WithSource - true or false to return the _source field or not, or a list of fields to return.
+//
+func (f AsyncSearchSubmit) WithSource(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Source = v
+	}
+}
+
+// WithSourceExcludes - a list of fields to exclude from the returned _source field.
+//
+func (f AsyncSearchSubmit) WithSourceExcludes(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SourceExcludes = v
+	}
+}
+
+// WithSourceIncludes - a list of fields to extract and return from the _source field.
+//
+func (f AsyncSearchSubmit) WithSourceIncludes(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SourceIncludes = v
+	}
+}
+
+// WithStats - specific 'tag' of the request for logging and statistical purposes.
+//
+func (f AsyncSearchSubmit) WithStats(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Stats = v
+	}
+}
+
+// WithStoredFields - a list of stored fields to return as part of a hit.
+//
+func (f AsyncSearchSubmit) WithStoredFields(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.StoredFields = v
+	}
+}
+
+// WithSuggestField - specify which field to use for suggestions.
+//
+func (f AsyncSearchSubmit) WithSuggestField(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SuggestField = v
+	}
+}
+
+// WithSuggestMode - specify suggest mode.
+//
+func (f AsyncSearchSubmit) WithSuggestMode(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SuggestMode = v
+	}
+}
+
+// WithSuggestSize - how many suggestions to return in response.
+//
+func (f AsyncSearchSubmit) WithSuggestSize(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SuggestSize = &v
+	}
+}
+
+// WithSuggestText - the source text for which the suggestions should be returned.
+//
+func (f AsyncSearchSubmit) WithSuggestText(v string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.SuggestText = v
+	}
+}
+
+// WithTerminateAfter - the maximum number of documents to collect for each shard, upon reaching which the query execution will terminate early..
+//
+func (f AsyncSearchSubmit) WithTerminateAfter(v int) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.TerminateAfter = &v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f AsyncSearchSubmit) WithTimeout(v time.Duration) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithTrackScores - whether to calculate and return scores even if they are not used for sorting.
+//
+func (f AsyncSearchSubmit) WithTrackScores(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.TrackScores = &v
+	}
+}
+
+// WithTrackTotalHits - indicate if the number of documents that match the query should be tracked.
+//
+func (f AsyncSearchSubmit) WithTrackTotalHits(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.TrackTotalHits = &v
+	}
+}
+
+// WithTypedKeys - specify whether aggregation and suggester names should be prefixed by their respective types in the response.
+//
+func (f AsyncSearchSubmit) WithTypedKeys(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.TypedKeys = &v
+	}
+}
+
+// WithVersion - specify whether to return document version as part of a hit.
+//
+func (f AsyncSearchSubmit) WithVersion(v bool) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Version = &v
+	}
+}
+
+// WithWaitForCompletionTimeout - specify the time that the request should block waiting for the final response.
+//
+func (f AsyncSearchSubmit) WithWaitForCompletionTimeout(v time.Duration) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.WaitForCompletionTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AsyncSearchSubmit) WithPretty() func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AsyncSearchSubmit) WithHuman() func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AsyncSearchSubmit) WithErrorTrace() func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AsyncSearchSubmit) WithFilterPath(v ...string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AsyncSearchSubmit) WithHeader(h map[string]string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AsyncSearchSubmit) WithOpaqueID(s string) func(*AsyncSearchSubmitRequest) {
+	return func(r *AsyncSearchSubmitRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.autoscaling.delete_autoscaling_policy.go b/esapi/api.xpack.autoscaling.delete_autoscaling_policy.go
new file mode 100644
index 0000000000..4d458d4a58
--- /dev/null
+++ b/esapi/api.xpack.autoscaling.delete_autoscaling_policy.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAutoscalingDeleteAutoscalingPolicyFunc(t Transport) AutoscalingDeleteAutoscalingPolicy {
+	return func(name string, o ...func(*AutoscalingDeleteAutoscalingPolicyRequest)) (*Response, error) {
+		var r = AutoscalingDeleteAutoscalingPolicyRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AutoscalingDeleteAutoscalingPolicy - Deletes an autoscaling policy. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-delete-autoscaling-policy.html.
+//
+type AutoscalingDeleteAutoscalingPolicy func(name string, o ...func(*AutoscalingDeleteAutoscalingPolicyRequest)) (*Response, error)
+
+// AutoscalingDeleteAutoscalingPolicyRequest configures the Autoscaling Delete Autoscaling Policy API request.
+//
+type AutoscalingDeleteAutoscalingPolicyRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AutoscalingDeleteAutoscalingPolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_autoscaling") + 1 + len("policy") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_autoscaling")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithContext(v context.Context) func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithPretty() func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithHuman() func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithErrorTrace() func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithFilterPath(v ...string) func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithHeader(h map[string]string) func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AutoscalingDeleteAutoscalingPolicy) WithOpaqueID(s string) func(*AutoscalingDeleteAutoscalingPolicyRequest) {
+	return func(r *AutoscalingDeleteAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.autoscaling.get_autoscaling_capacity.go b/esapi/api.xpack.autoscaling.get_autoscaling_capacity.go
new file mode 100644
index 0000000000..f9aacc1f9d
--- /dev/null
+++ b/esapi/api.xpack.autoscaling.get_autoscaling_capacity.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAutoscalingGetAutoscalingCapacityFunc(t Transport) AutoscalingGetAutoscalingCapacity {
+	return func(o ...func(*AutoscalingGetAutoscalingCapacityRequest)) (*Response, error) {
+		var r = AutoscalingGetAutoscalingCapacityRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AutoscalingGetAutoscalingCapacity - Gets the current autoscaling capacity based on the configured autoscaling policy. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-get-autoscaling-capacity.html.
+//
+type AutoscalingGetAutoscalingCapacity func(o ...func(*AutoscalingGetAutoscalingCapacityRequest)) (*Response, error)
+
+// AutoscalingGetAutoscalingCapacityRequest configures the Autoscaling Get Autoscaling Capacity API request.
+//
+type AutoscalingGetAutoscalingCapacityRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AutoscalingGetAutoscalingCapacityRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_autoscaling/capacity"))
+	path.WriteString("/_autoscaling/capacity")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithContext(v context.Context) func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithPretty() func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithHuman() func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithErrorTrace() func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithFilterPath(v ...string) func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithHeader(h map[string]string) func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingCapacity) WithOpaqueID(s string) func(*AutoscalingGetAutoscalingCapacityRequest) {
+	return func(r *AutoscalingGetAutoscalingCapacityRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.autoscaling.get_autoscaling_decision.go b/esapi/api.xpack.autoscaling.get_autoscaling_decision.go
new file mode 100644
index 0000000000..b5e957eabc
--- /dev/null
+++ b/esapi/api.xpack.autoscaling.get_autoscaling_decision.go
@@ -0,0 +1,198 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.10.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAutoscalingGetAutoscalingDecisionFunc(t Transport) AutoscalingGetAutoscalingDecision {
+	return func(o ...func(*AutoscalingGetAutoscalingDecisionRequest)) (*Response, error) {
+		var r = AutoscalingGetAutoscalingDecisionRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AutoscalingGetAutoscalingDecision - Gets the current autoscaling decision based on the configured autoscaling policy, indicating whether or not autoscaling is needed.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-get-autoscaling-decision.html.
+//
+type AutoscalingGetAutoscalingDecision func(o ...func(*AutoscalingGetAutoscalingDecisionRequest)) (*Response, error)
+
+// AutoscalingGetAutoscalingDecisionRequest configures the Autoscaling Get Autoscaling Decision API request.
+//
+type AutoscalingGetAutoscalingDecisionRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AutoscalingGetAutoscalingDecisionRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_autoscaling/decision"))
+	path.WriteString("/_autoscaling/decision")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AutoscalingGetAutoscalingDecision) WithContext(v context.Context) func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AutoscalingGetAutoscalingDecision) WithPretty() func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AutoscalingGetAutoscalingDecision) WithHuman() func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AutoscalingGetAutoscalingDecision) WithErrorTrace() func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AutoscalingGetAutoscalingDecision) WithFilterPath(v ...string) func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingDecision) WithHeader(h map[string]string) func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingDecision) WithOpaqueID(s string) func(*AutoscalingGetAutoscalingDecisionRequest) {
+	return func(r *AutoscalingGetAutoscalingDecisionRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.autoscaling.get_autoscaling_policy.go b/esapi/api.xpack.autoscaling.get_autoscaling_policy.go
new file mode 100644
index 0000000000..702372e371
--- /dev/null
+++ b/esapi/api.xpack.autoscaling.get_autoscaling_policy.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newAutoscalingGetAutoscalingPolicyFunc(t Transport) AutoscalingGetAutoscalingPolicy {
+	return func(name string, o ...func(*AutoscalingGetAutoscalingPolicyRequest)) (*Response, error) {
+		var r = AutoscalingGetAutoscalingPolicyRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AutoscalingGetAutoscalingPolicy - Retrieves an autoscaling policy. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-get-autoscaling-policy.html.
+//
+type AutoscalingGetAutoscalingPolicy func(name string, o ...func(*AutoscalingGetAutoscalingPolicyRequest)) (*Response, error)
+
+// AutoscalingGetAutoscalingPolicyRequest configures the Autoscaling Get Autoscaling Policy API request.
+//
+type AutoscalingGetAutoscalingPolicyRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AutoscalingGetAutoscalingPolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_autoscaling") + 1 + len("policy") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_autoscaling")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithContext(v context.Context) func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithPretty() func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithHuman() func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithErrorTrace() func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithFilterPath(v ...string) func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithHeader(h map[string]string) func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AutoscalingGetAutoscalingPolicy) WithOpaqueID(s string) func(*AutoscalingGetAutoscalingPolicyRequest) {
+	return func(r *AutoscalingGetAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.autoscaling.put_autoscaling_policy.go b/esapi/api.xpack.autoscaling.put_autoscaling_policy.go
new file mode 100644
index 0000000000..dc630a7369
--- /dev/null
+++ b/esapi/api.xpack.autoscaling.put_autoscaling_policy.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newAutoscalingPutAutoscalingPolicyFunc(t Transport) AutoscalingPutAutoscalingPolicy {
+	return func(name string, body io.Reader, o ...func(*AutoscalingPutAutoscalingPolicyRequest)) (*Response, error) {
+		var r = AutoscalingPutAutoscalingPolicyRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// AutoscalingPutAutoscalingPolicy - Creates a new autoscaling policy. Designed for indirect use by ECE/ESS and ECK. Direct use is not supported.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-put-autoscaling-policy.html.
+//
+type AutoscalingPutAutoscalingPolicy func(name string, body io.Reader, o ...func(*AutoscalingPutAutoscalingPolicyRequest)) (*Response, error)
+
+// AutoscalingPutAutoscalingPolicyRequest configures the Autoscaling Put Autoscaling Policy API request.
+//
+type AutoscalingPutAutoscalingPolicyRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r AutoscalingPutAutoscalingPolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_autoscaling") + 1 + len("policy") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_autoscaling")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithContext(v context.Context) func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithPretty() func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithHuman() func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithErrorTrace() func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithFilterPath(v ...string) func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithHeader(h map[string]string) func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f AutoscalingPutAutoscalingPolicy) WithOpaqueID(s string) func(*AutoscalingPutAutoscalingPolicyRequest) {
+	return func(r *AutoscalingPutAutoscalingPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.cat.ml_data_frame_analytics.go b/esapi/api.xpack.cat.ml_data_frame_analytics.go
new file mode 100644
index 0000000000..2e859f0c49
--- /dev/null
+++ b/esapi/api.xpack.cat.ml_data_frame_analytics.go
@@ -0,0 +1,323 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newCatMLDataFrameAnalyticsFunc(t Transport) CatMLDataFrameAnalytics {
+	return func(o ...func(*CatMLDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = CatMLDataFrameAnalyticsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CatMLDataFrameAnalytics - Gets configuration and usage information about data frame analytics jobs.
+//
+// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/cat-dfanalytics.html.
+//
+type CatMLDataFrameAnalytics func(o ...func(*CatMLDataFrameAnalyticsRequest)) (*Response, error)
+
+// CatMLDataFrameAnalyticsRequest configures the CatML Data Frame Analytics API request.
+//
+type CatMLDataFrameAnalyticsRequest struct {
+	DocumentID string
+
+	AllowNoMatch *bool
+	Bytes        string
+	Format       string
+	H            []string
+	Help         *bool
+	S            []string
+	Time         string
+	V            *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CatMLDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_cat") + 1 + len("ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_cat")
+	path.WriteString("/")
+	path.WriteString("ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	if r.DocumentID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Bytes != "" {
+		params["bytes"] = r.Bytes
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if len(r.H) > 0 {
+		params["h"] = strings.Join(r.H, ",")
+	}
+
+	if r.Help != nil {
+		params["help"] = strconv.FormatBool(*r.Help)
+	}
+
+	if len(r.S) > 0 {
+		params["s"] = strings.Join(r.S, ",")
+	}
+
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
+	if r.V != nil {
+		params["v"] = strconv.FormatBool(*r.V)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CatMLDataFrameAnalytics) WithContext(v context.Context) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDocumentID - the ID of the data frame analytics to fetch.
+//
+func (f CatMLDataFrameAnalytics) WithDocumentID(v string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.DocumentID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no configs. (this includes `_all` string or when no configs have been specified).
+//
+func (f CatMLDataFrameAnalytics) WithAllowNoMatch(v bool) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithBytes - the unit in which to display byte values.
+//
+func (f CatMLDataFrameAnalytics) WithBytes(v string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Bytes = v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f CatMLDataFrameAnalytics) WithFormat(v string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Format = v
+	}
+}
+
+// WithH - comma-separated list of column names to display.
+//
+func (f CatMLDataFrameAnalytics) WithH(v ...string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.H = v
+	}
+}
+
+// WithHelp - return help information.
+//
+func (f CatMLDataFrameAnalytics) WithHelp(v bool) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Help = &v
+	}
+}
+
+// WithS - comma-separated list of column names or column aliases to sort by.
+//
+func (f CatMLDataFrameAnalytics) WithS(v ...string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.S = v
+	}
+}
+
+// WithTime - the unit in which to display time values.
+//
+func (f CatMLDataFrameAnalytics) WithTime(v string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Time = v
+	}
+}
+
+// WithV - verbose mode. display column headers.
+//
+func (f CatMLDataFrameAnalytics) WithV(v bool) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.V = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CatMLDataFrameAnalytics) WithPretty() func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CatMLDataFrameAnalytics) WithHuman() func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CatMLDataFrameAnalytics) WithErrorTrace() func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CatMLDataFrameAnalytics) WithFilterPath(v ...string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatMLDataFrameAnalytics) WithHeader(h map[string]string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatMLDataFrameAnalytics) WithOpaqueID(s string) func(*CatMLDataFrameAnalyticsRequest) {
+	return func(r *CatMLDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.cat.ml_datafeeds.go b/esapi/api.xpack.cat.ml_datafeeds.go
new file mode 100644
index 0000000000..b78c0ba0b6
--- /dev/null
+++ b/esapi/api.xpack.cat.ml_datafeeds.go
@@ -0,0 +1,321 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newCatMLDatafeedsFunc(t Transport) CatMLDatafeeds {
+	return func(o ...func(*CatMLDatafeedsRequest)) (*Response, error) {
+		var r = CatMLDatafeedsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CatMLDatafeeds - Gets configuration and usage information about datafeeds.
+//
+// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/cat-datafeeds.html.
+//
+type CatMLDatafeeds func(o ...func(*CatMLDatafeedsRequest)) (*Response, error)
+
+// CatMLDatafeedsRequest configures the CatML Datafeeds API request.
+//
+type CatMLDatafeedsRequest struct {
+	DatafeedID string
+
+	AllowNoDatafeeds *bool
+	AllowNoMatch     *bool
+	Format           string
+	H                []string
+	Help             *bool
+	S                []string
+	Time             string
+	V                *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CatMLDatafeedsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_cat") + 1 + len("ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID))
+	path.WriteString("/")
+	path.WriteString("_cat")
+	path.WriteString("/")
+	path.WriteString("ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	if r.DatafeedID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DatafeedID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoDatafeeds != nil {
+		params["allow_no_datafeeds"] = strconv.FormatBool(*r.AllowNoDatafeeds)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if len(r.H) > 0 {
+		params["h"] = strings.Join(r.H, ",")
+	}
+
+	if r.Help != nil {
+		params["help"] = strconv.FormatBool(*r.Help)
+	}
+
+	if len(r.S) > 0 {
+		params["s"] = strings.Join(r.S, ",")
+	}
+
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
+	if r.V != nil {
+		params["v"] = strconv.FormatBool(*r.V)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CatMLDatafeeds) WithContext(v context.Context) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDatafeedID - the ID of the datafeeds stats to fetch.
+//
+func (f CatMLDatafeeds) WithDatafeedID(v string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.DatafeedID = v
+	}
+}
+
+// WithAllowNoDatafeeds - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f CatMLDatafeeds) WithAllowNoDatafeeds(v bool) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.AllowNoDatafeeds = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f CatMLDatafeeds) WithAllowNoMatch(v bool) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f CatMLDatafeeds) WithFormat(v string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.Format = v
+	}
+}
+
+// WithH - comma-separated list of column names to display.
+//
+func (f CatMLDatafeeds) WithH(v ...string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.H = v
+	}
+}
+
+// WithHelp - return help information.
+//
+func (f CatMLDatafeeds) WithHelp(v bool) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.Help = &v
+	}
+}
+
+// WithS - comma-separated list of column names or column aliases to sort by.
+//
+func (f CatMLDatafeeds) WithS(v ...string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.S = v
+	}
+}
+
+// WithTime - the unit in which to display time values.
+//
+func (f CatMLDatafeeds) WithTime(v string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.Time = v
+	}
+}
+
+// WithV - verbose mode. display column headers.
+//
+func (f CatMLDatafeeds) WithV(v bool) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.V = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CatMLDatafeeds) WithPretty() func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CatMLDatafeeds) WithHuman() func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CatMLDatafeeds) WithErrorTrace() func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CatMLDatafeeds) WithFilterPath(v ...string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatMLDatafeeds) WithHeader(h map[string]string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatMLDatafeeds) WithOpaqueID(s string) func(*CatMLDatafeedsRequest) {
+	return func(r *CatMLDatafeedsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.cat.ml_jobs.go b/esapi/api.xpack.cat.ml_jobs.go
new file mode 100644
index 0000000000..1bf3069f09
--- /dev/null
+++ b/esapi/api.xpack.cat.ml_jobs.go
@@ -0,0 +1,334 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newCatMLJobsFunc(t Transport) CatMLJobs {
+	return func(o ...func(*CatMLJobsRequest)) (*Response, error) {
+		var r = CatMLJobsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CatMLJobs - Gets configuration and usage information about anomaly detection jobs.
+//
+// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/cat-anomaly-detectors.html.
+//
+type CatMLJobs func(o ...func(*CatMLJobsRequest)) (*Response, error)
+
+// CatMLJobsRequest configures the CatML Jobs API request.
+//
+type CatMLJobsRequest struct {
+	JobID string
+
+	AllowNoJobs  *bool
+	AllowNoMatch *bool
+	Bytes        string
+	Format       string
+	H            []string
+	Help         *bool
+	S            []string
+	Time         string
+	V            *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CatMLJobsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_cat") + 1 + len("ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_cat")
+	path.WriteString("/")
+	path.WriteString("ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	if r.JobID != "" {
+		path.WriteString("/")
+		path.WriteString(r.JobID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoJobs != nil {
+		params["allow_no_jobs"] = strconv.FormatBool(*r.AllowNoJobs)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Bytes != "" {
+		params["bytes"] = r.Bytes
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if len(r.H) > 0 {
+		params["h"] = strings.Join(r.H, ",")
+	}
+
+	if r.Help != nil {
+		params["help"] = strconv.FormatBool(*r.Help)
+	}
+
+	if len(r.S) > 0 {
+		params["s"] = strings.Join(r.S, ",")
+	}
+
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
+	if r.V != nil {
+		params["v"] = strconv.FormatBool(*r.V)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CatMLJobs) WithContext(v context.Context) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithJobID - the ID of the jobs stats to fetch.
+//
+func (f CatMLJobs) WithJobID(v string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.JobID = v
+	}
+}
+
+// WithAllowNoJobs - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f CatMLJobs) WithAllowNoJobs(v bool) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.AllowNoJobs = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f CatMLJobs) WithAllowNoMatch(v bool) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithBytes - the unit in which to display byte values.
+//
+func (f CatMLJobs) WithBytes(v string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Bytes = v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f CatMLJobs) WithFormat(v string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Format = v
+	}
+}
+
+// WithH - comma-separated list of column names to display.
+//
+func (f CatMLJobs) WithH(v ...string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.H = v
+	}
+}
+
+// WithHelp - return help information.
+//
+func (f CatMLJobs) WithHelp(v bool) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Help = &v
+	}
+}
+
+// WithS - comma-separated list of column names or column aliases to sort by.
+//
+func (f CatMLJobs) WithS(v ...string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.S = v
+	}
+}
+
+// WithTime - the unit in which to display time values.
+//
+func (f CatMLJobs) WithTime(v string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Time = v
+	}
+}
+
+// WithV - verbose mode. display column headers.
+//
+func (f CatMLJobs) WithV(v bool) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.V = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CatMLJobs) WithPretty() func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CatMLJobs) WithHuman() func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CatMLJobs) WithErrorTrace() func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CatMLJobs) WithFilterPath(v ...string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatMLJobs) WithHeader(h map[string]string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatMLJobs) WithOpaqueID(s string) func(*CatMLJobsRequest) {
+	return func(r *CatMLJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.cat.ml_trained_models.go b/esapi/api.xpack.cat.ml_trained_models.go
new file mode 100644
index 0000000000..07edab3a02
--- /dev/null
+++ b/esapi/api.xpack.cat.ml_trained_models.go
@@ -0,0 +1,347 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newCatMLTrainedModelsFunc(t Transport) CatMLTrainedModels {
+	return func(o ...func(*CatMLTrainedModelsRequest)) (*Response, error) {
+		var r = CatMLTrainedModelsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CatMLTrainedModels - Gets configuration and usage information about inference trained models.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/cat-trained-model.html.
+//
+type CatMLTrainedModels func(o ...func(*CatMLTrainedModelsRequest)) (*Response, error)
+
+// CatMLTrainedModelsRequest configures the CatML Trained Models API request.
+//
+type CatMLTrainedModelsRequest struct {
+	ModelID string
+
+	AllowNoMatch *bool
+	Bytes        string
+	Format       string
+	From         *int
+	H            []string
+	Help         *bool
+	S            []string
+	Size         *int
+	Time         string
+	V            *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CatMLTrainedModelsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_cat") + 1 + len("ml") + 1 + len("trained_models") + 1 + len(r.ModelID))
+	path.WriteString("/")
+	path.WriteString("_cat")
+	path.WriteString("/")
+	path.WriteString("ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	if r.ModelID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ModelID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Bytes != "" {
+		params["bytes"] = r.Bytes
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if len(r.H) > 0 {
+		params["h"] = strings.Join(r.H, ",")
+	}
+
+	if r.Help != nil {
+		params["help"] = strconv.FormatBool(*r.Help)
+	}
+
+	if len(r.S) > 0 {
+		params["s"] = strings.Join(r.S, ",")
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
+	if r.V != nil {
+		params["v"] = strconv.FormatBool(*r.V)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CatMLTrainedModels) WithContext(v context.Context) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithModelID - the ID of the trained models stats to fetch.
+//
+func (f CatMLTrainedModels) WithModelID(v string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.ModelID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no trained models. (this includes `_all` string or when no trained models have been specified).
+//
+func (f CatMLTrainedModels) WithAllowNoMatch(v bool) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithBytes - the unit in which to display byte values.
+//
+func (f CatMLTrainedModels) WithBytes(v string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Bytes = v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f CatMLTrainedModels) WithFormat(v string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Format = v
+	}
+}
+
+// WithFrom - skips a number of trained models.
+//
+func (f CatMLTrainedModels) WithFrom(v int) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.From = &v
+	}
+}
+
+// WithH - comma-separated list of column names to display.
+//
+func (f CatMLTrainedModels) WithH(v ...string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.H = v
+	}
+}
+
+// WithHelp - return help information.
+//
+func (f CatMLTrainedModels) WithHelp(v bool) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Help = &v
+	}
+}
+
+// WithS - comma-separated list of column names or column aliases to sort by.
+//
+func (f CatMLTrainedModels) WithS(v ...string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.S = v
+	}
+}
+
+// WithSize - specifies a max number of trained models to get.
+//
+func (f CatMLTrainedModels) WithSize(v int) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithTime - the unit in which to display time values.
+//
+func (f CatMLTrainedModels) WithTime(v string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Time = v
+	}
+}
+
+// WithV - verbose mode. display column headers.
+//
+func (f CatMLTrainedModels) WithV(v bool) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.V = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CatMLTrainedModels) WithPretty() func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CatMLTrainedModels) WithHuman() func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CatMLTrainedModels) WithErrorTrace() func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CatMLTrainedModels) WithFilterPath(v ...string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatMLTrainedModels) WithHeader(h map[string]string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatMLTrainedModels) WithOpaqueID(s string) func(*CatMLTrainedModelsRequest) {
+	return func(r *CatMLTrainedModelsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.cat.transforms.go b/esapi/api.xpack.cat.transforms.go
new file mode 100644
index 0000000000..e466046dca
--- /dev/null
+++ b/esapi/api.xpack.cat.transforms.go
@@ -0,0 +1,332 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newCatTransformsFunc(t Transport) CatTransforms {
+	return func(o ...func(*CatTransformsRequest)) (*Response, error) {
+		var r = CatTransformsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CatTransforms - Gets configuration and usage information about transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/cat-transforms.html.
+//
+type CatTransforms func(o ...func(*CatTransformsRequest)) (*Response, error)
+
+// CatTransformsRequest configures the Cat Transforms API request.
+//
+type CatTransformsRequest struct {
+	TransformID string
+
+	AllowNoMatch *bool
+	Format       string
+	From         *int
+	H            []string
+	Help         *bool
+	S            []string
+	Size         *int
+	Time         string
+	V            *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CatTransformsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_cat") + 1 + len("transforms") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_cat")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	if r.TransformID != "" {
+		path.WriteString("/")
+		path.WriteString(r.TransformID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if len(r.H) > 0 {
+		params["h"] = strings.Join(r.H, ",")
+	}
+
+	if r.Help != nil {
+		params["help"] = strconv.FormatBool(*r.Help)
+	}
+
+	if len(r.S) > 0 {
+		params["s"] = strings.Join(r.S, ",")
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Time != "" {
+		params["time"] = r.Time
+	}
+
+	if r.V != nil {
+		params["v"] = strconv.FormatBool(*r.V)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CatTransforms) WithContext(v context.Context) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTransformID - the ID of the transform for which to get stats. '_all' or '*' implies all transforms.
+//
+func (f CatTransforms) WithTransformID(v string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.TransformID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f CatTransforms) WithAllowNoMatch(v bool) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f CatTransforms) WithFormat(v string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Format = v
+	}
+}
+
+// WithFrom - skips a number of transform configs, defaults to 0.
+//
+func (f CatTransforms) WithFrom(v int) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.From = &v
+	}
+}
+
+// WithH - comma-separated list of column names to display.
+//
+func (f CatTransforms) WithH(v ...string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.H = v
+	}
+}
+
+// WithHelp - return help information.
+//
+func (f CatTransforms) WithHelp(v bool) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Help = &v
+	}
+}
+
+// WithS - comma-separated list of column names or column aliases to sort by.
+//
+func (f CatTransforms) WithS(v ...string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.S = v
+	}
+}
+
+// WithSize - specifies a max number of transforms to get, defaults to 100.
+//
+func (f CatTransforms) WithSize(v int) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithTime - the unit in which to display time values.
+//
+func (f CatTransforms) WithTime(v string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Time = v
+	}
+}
+
+// WithV - verbose mode. display column headers.
+//
+func (f CatTransforms) WithV(v bool) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.V = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CatTransforms) WithPretty() func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CatTransforms) WithHuman() func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CatTransforms) WithErrorTrace() func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CatTransforms) WithFilterPath(v ...string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CatTransforms) WithHeader(h map[string]string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CatTransforms) WithOpaqueID(s string) func(*CatTransformsRequest) {
+	return func(r *CatTransformsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.delete_auto_follow_pattern.go b/esapi/api.xpack.ccr.delete_auto_follow_pattern.go
new file mode 100644
index 0000000000..e5b9aac32f
--- /dev/null
+++ b/esapi/api.xpack.ccr.delete_auto_follow_pattern.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRDeleteAutoFollowPatternFunc(t Transport) CCRDeleteAutoFollowPattern {
+	return func(name string, o ...func(*CCRDeleteAutoFollowPatternRequest)) (*Response, error) {
+		var r = CCRDeleteAutoFollowPatternRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRDeleteAutoFollowPattern - Deletes auto-follow patterns.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-delete-auto-follow-pattern.html.
+//
+type CCRDeleteAutoFollowPattern func(name string, o ...func(*CCRDeleteAutoFollowPatternRequest)) (*Response, error)
+
+// CCRDeleteAutoFollowPatternRequest configures the CCR Delete Auto Follow Pattern API request.
+//
+type CCRDeleteAutoFollowPatternRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRDeleteAutoFollowPatternRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ccr") + 1 + len("auto_follow") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("auto_follow")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRDeleteAutoFollowPattern) WithContext(v context.Context) func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRDeleteAutoFollowPattern) WithPretty() func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRDeleteAutoFollowPattern) WithHuman() func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRDeleteAutoFollowPattern) WithErrorTrace() func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRDeleteAutoFollowPattern) WithFilterPath(v ...string) func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRDeleteAutoFollowPattern) WithHeader(h map[string]string) func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRDeleteAutoFollowPattern) WithOpaqueID(s string) func(*CCRDeleteAutoFollowPatternRequest) {
+	return func(r *CCRDeleteAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.follow.go b/esapi/api.xpack.ccr.follow.go
new file mode 100644
index 0000000000..91150f391b
--- /dev/null
+++ b/esapi/api.xpack.ccr.follow.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newCCRFollowFunc(t Transport) CCRFollow {
+	return func(index string, body io.Reader, o ...func(*CCRFollowRequest)) (*Response, error) {
+		var r = CCRFollowRequest{Index: index, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRFollow - Creates a new follower index configured to follow the referenced leader index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-put-follow.html.
+//
+type CCRFollow func(index string, body io.Reader, o ...func(*CCRFollowRequest)) (*Response, error)
+
+// CCRFollowRequest configures the CCR Follow API request.
+//
+type CCRFollowRequest struct {
+	Index string
+
+	Body io.Reader
+
+	WaitForActiveShards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRFollowRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ccr") + 1 + len("follow"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("follow")
+
+	params = make(map[string]string)
+
+	if r.WaitForActiveShards != "" {
+		params["wait_for_active_shards"] = r.WaitForActiveShards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRFollow) WithContext(v context.Context) func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.ctx = v
+	}
+}
+
+// WithWaitForActiveShards - sets the number of shard copies that must be active before returning. defaults to 0. set to `all` for all shard copies, otherwise set to any non-negative value less than or equal to the total number of copies for the shard (number of replicas + 1).
+//
+func (f CCRFollow) WithWaitForActiveShards(v string) func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.WaitForActiveShards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRFollow) WithPretty() func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRFollow) WithHuman() func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRFollow) WithErrorTrace() func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRFollow) WithFilterPath(v ...string) func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRFollow) WithHeader(h map[string]string) func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRFollow) WithOpaqueID(s string) func(*CCRFollowRequest) {
+	return func(r *CCRFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.follow_info.go b/esapi/api.xpack.ccr.follow_info.go
new file mode 100644
index 0000000000..c500f347ff
--- /dev/null
+++ b/esapi/api.xpack.ccr.follow_info.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRFollowInfoFunc(t Transport) CCRFollowInfo {
+	return func(index []string, o ...func(*CCRFollowInfoRequest)) (*Response, error) {
+		var r = CCRFollowInfoRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRFollowInfo - Retrieves information about all follower indices, including parameters and status for each follower index
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html.
+//
+type CCRFollowInfo func(index []string, o ...func(*CCRFollowInfoRequest)) (*Response, error)
+
+// CCRFollowInfoRequest configures the CCR Follow Info API request.
+//
+type CCRFollowInfoRequest struct {
+	Index []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRFollowInfoRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_ccr") + 1 + len("info"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("info")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRFollowInfo) WithContext(v context.Context) func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRFollowInfo) WithPretty() func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRFollowInfo) WithHuman() func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRFollowInfo) WithErrorTrace() func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRFollowInfo) WithFilterPath(v ...string) func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRFollowInfo) WithHeader(h map[string]string) func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRFollowInfo) WithOpaqueID(s string) func(*CCRFollowInfoRequest) {
+	return func(r *CCRFollowInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.follow_stats.go b/esapi/api.xpack.ccr.follow_stats.go
new file mode 100644
index 0000000000..e4200c5af4
--- /dev/null
+++ b/esapi/api.xpack.ccr.follow_stats.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRFollowStatsFunc(t Transport) CCRFollowStats {
+	return func(index []string, o ...func(*CCRFollowStatsRequest)) (*Response, error) {
+		var r = CCRFollowStatsRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRFollowStats - Retrieves follower stats. return shard-level stats about the following tasks associated with each shard for the specified indices.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html.
+//
+type CCRFollowStats func(index []string, o ...func(*CCRFollowStatsRequest)) (*Response, error)
+
+// CCRFollowStatsRequest configures the CCR Follow Stats API request.
+//
+type CCRFollowStatsRequest struct {
+	Index []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRFollowStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_ccr") + 1 + len("stats"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRFollowStats) WithContext(v context.Context) func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRFollowStats) WithPretty() func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRFollowStats) WithHuman() func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRFollowStats) WithErrorTrace() func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRFollowStats) WithFilterPath(v ...string) func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRFollowStats) WithHeader(h map[string]string) func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRFollowStats) WithOpaqueID(s string) func(*CCRFollowStatsRequest) {
+	return func(r *CCRFollowStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.forget_follower.go b/esapi/api.xpack.ccr.forget_follower.go
new file mode 100644
index 0000000000..a7744146cc
--- /dev/null
+++ b/esapi/api.xpack.ccr.forget_follower.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newCCRForgetFollowerFunc(t Transport) CCRForgetFollower {
+	return func(index string, body io.Reader, o ...func(*CCRForgetFollowerRequest)) (*Response, error) {
+		var r = CCRForgetFollowerRequest{Index: index, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRForgetFollower - Removes the follower retention leases from the leader.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-forget-follower.html.
+//
+type CCRForgetFollower func(index string, body io.Reader, o ...func(*CCRForgetFollowerRequest)) (*Response, error)
+
+// CCRForgetFollowerRequest configures the CCR Forget Follower API request.
+//
+type CCRForgetFollowerRequest struct {
+	Index string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRForgetFollowerRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ccr") + 1 + len("forget_follower"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("forget_follower")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRForgetFollower) WithContext(v context.Context) func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRForgetFollower) WithPretty() func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRForgetFollower) WithHuman() func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRForgetFollower) WithErrorTrace() func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRForgetFollower) WithFilterPath(v ...string) func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRForgetFollower) WithHeader(h map[string]string) func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRForgetFollower) WithOpaqueID(s string) func(*CCRForgetFollowerRequest) {
+	return func(r *CCRForgetFollowerRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.get_auto_follow_pattern.go b/esapi/api.xpack.ccr.get_auto_follow_pattern.go
new file mode 100644
index 0000000000..a99412d3a0
--- /dev/null
+++ b/esapi/api.xpack.ccr.get_auto_follow_pattern.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRGetAutoFollowPatternFunc(t Transport) CCRGetAutoFollowPattern {
+	return func(o ...func(*CCRGetAutoFollowPatternRequest)) (*Response, error) {
+		var r = CCRGetAutoFollowPatternRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRGetAutoFollowPattern - Gets configured auto-follow patterns. Returns the specified auto-follow pattern collection.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-auto-follow-pattern.html.
+//
+type CCRGetAutoFollowPattern func(o ...func(*CCRGetAutoFollowPatternRequest)) (*Response, error)
+
+// CCRGetAutoFollowPatternRequest configures the CCR Get Auto Follow Pattern API request.
+//
+type CCRGetAutoFollowPatternRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRGetAutoFollowPatternRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ccr") + 1 + len("auto_follow") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("auto_follow")
+	if r.Name != "" {
+		path.WriteString("/")
+		path.WriteString(r.Name)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRGetAutoFollowPattern) WithContext(v context.Context) func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - the name of the auto follow pattern..
+//
+func (f CCRGetAutoFollowPattern) WithName(v string) func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRGetAutoFollowPattern) WithPretty() func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRGetAutoFollowPattern) WithHuman() func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRGetAutoFollowPattern) WithErrorTrace() func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRGetAutoFollowPattern) WithFilterPath(v ...string) func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRGetAutoFollowPattern) WithHeader(h map[string]string) func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRGetAutoFollowPattern) WithOpaqueID(s string) func(*CCRGetAutoFollowPatternRequest) {
+	return func(r *CCRGetAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.pause_auto_follow_pattern.go b/esapi/api.xpack.ccr.pause_auto_follow_pattern.go
new file mode 100644
index 0000000000..e62873a6e1
--- /dev/null
+++ b/esapi/api.xpack.ccr.pause_auto_follow_pattern.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRPauseAutoFollowPatternFunc(t Transport) CCRPauseAutoFollowPattern {
+	return func(name string, o ...func(*CCRPauseAutoFollowPatternRequest)) (*Response, error) {
+		var r = CCRPauseAutoFollowPatternRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRPauseAutoFollowPattern - Pauses an auto-follow pattern
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-pause-auto-follow-pattern.html.
+//
+type CCRPauseAutoFollowPattern func(name string, o ...func(*CCRPauseAutoFollowPatternRequest)) (*Response, error)
+
+// CCRPauseAutoFollowPatternRequest configures the CCR Pause Auto Follow Pattern API request.
+//
+type CCRPauseAutoFollowPatternRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRPauseAutoFollowPatternRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ccr") + 1 + len("auto_follow") + 1 + len(r.Name) + 1 + len("pause"))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("auto_follow")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+	path.WriteString("/")
+	path.WriteString("pause")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRPauseAutoFollowPattern) WithContext(v context.Context) func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRPauseAutoFollowPattern) WithPretty() func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRPauseAutoFollowPattern) WithHuman() func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRPauseAutoFollowPattern) WithErrorTrace() func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRPauseAutoFollowPattern) WithFilterPath(v ...string) func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRPauseAutoFollowPattern) WithHeader(h map[string]string) func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRPauseAutoFollowPattern) WithOpaqueID(s string) func(*CCRPauseAutoFollowPatternRequest) {
+	return func(r *CCRPauseAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.pause_follow.go b/esapi/api.xpack.ccr.pause_follow.go
new file mode 100644
index 0000000000..6cc1e0da12
--- /dev/null
+++ b/esapi/api.xpack.ccr.pause_follow.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRPauseFollowFunc(t Transport) CCRPauseFollow {
+	return func(index string, o ...func(*CCRPauseFollowRequest)) (*Response, error) {
+		var r = CCRPauseFollowRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRPauseFollow - Pauses a follower index. The follower index will not fetch any additional operations from the leader index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-pause-follow.html.
+//
+type CCRPauseFollow func(index string, o ...func(*CCRPauseFollowRequest)) (*Response, error)
+
+// CCRPauseFollowRequest configures the CCR Pause Follow API request.
+//
+type CCRPauseFollowRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRPauseFollowRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ccr") + 1 + len("pause_follow"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("pause_follow")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRPauseFollow) WithContext(v context.Context) func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRPauseFollow) WithPretty() func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRPauseFollow) WithHuman() func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRPauseFollow) WithErrorTrace() func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRPauseFollow) WithFilterPath(v ...string) func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRPauseFollow) WithHeader(h map[string]string) func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRPauseFollow) WithOpaqueID(s string) func(*CCRPauseFollowRequest) {
+	return func(r *CCRPauseFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.put_auto_follow_pattern.go b/esapi/api.xpack.ccr.put_auto_follow_pattern.go
new file mode 100644
index 0000000000..72442b83b0
--- /dev/null
+++ b/esapi/api.xpack.ccr.put_auto_follow_pattern.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newCCRPutAutoFollowPatternFunc(t Transport) CCRPutAutoFollowPattern {
+	return func(name string, body io.Reader, o ...func(*CCRPutAutoFollowPatternRequest)) (*Response, error) {
+		var r = CCRPutAutoFollowPatternRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRPutAutoFollowPattern - Creates a new named collection of auto-follow patterns against a specified remote cluster. Newly created indices on the remote cluster matching any of the specified patterns will be automatically configured as follower indices.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-put-auto-follow-pattern.html.
+//
+type CCRPutAutoFollowPattern func(name string, body io.Reader, o ...func(*CCRPutAutoFollowPatternRequest)) (*Response, error)
+
+// CCRPutAutoFollowPatternRequest configures the CCR Put Auto Follow Pattern API request.
+//
+type CCRPutAutoFollowPatternRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRPutAutoFollowPatternRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ccr") + 1 + len("auto_follow") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("auto_follow")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRPutAutoFollowPattern) WithContext(v context.Context) func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRPutAutoFollowPattern) WithPretty() func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRPutAutoFollowPattern) WithHuman() func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRPutAutoFollowPattern) WithErrorTrace() func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRPutAutoFollowPattern) WithFilterPath(v ...string) func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRPutAutoFollowPattern) WithHeader(h map[string]string) func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRPutAutoFollowPattern) WithOpaqueID(s string) func(*CCRPutAutoFollowPatternRequest) {
+	return func(r *CCRPutAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.resume_auto_follow_pattern.go b/esapi/api.xpack.ccr.resume_auto_follow_pattern.go
new file mode 100644
index 0000000000..800fb50e34
--- /dev/null
+++ b/esapi/api.xpack.ccr.resume_auto_follow_pattern.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRResumeAutoFollowPatternFunc(t Transport) CCRResumeAutoFollowPattern {
+	return func(name string, o ...func(*CCRResumeAutoFollowPatternRequest)) (*Response, error) {
+		var r = CCRResumeAutoFollowPatternRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRResumeAutoFollowPattern - Resumes an auto-follow pattern that has been paused
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-resume-auto-follow-pattern.html.
+//
+type CCRResumeAutoFollowPattern func(name string, o ...func(*CCRResumeAutoFollowPatternRequest)) (*Response, error)
+
+// CCRResumeAutoFollowPatternRequest configures the CCR Resume Auto Follow Pattern API request.
+//
+type CCRResumeAutoFollowPatternRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRResumeAutoFollowPatternRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ccr") + 1 + len("auto_follow") + 1 + len(r.Name) + 1 + len("resume"))
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("auto_follow")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+	path.WriteString("/")
+	path.WriteString("resume")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRResumeAutoFollowPattern) WithContext(v context.Context) func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRResumeAutoFollowPattern) WithPretty() func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRResumeAutoFollowPattern) WithHuman() func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRResumeAutoFollowPattern) WithErrorTrace() func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRResumeAutoFollowPattern) WithFilterPath(v ...string) func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRResumeAutoFollowPattern) WithHeader(h map[string]string) func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRResumeAutoFollowPattern) WithOpaqueID(s string) func(*CCRResumeAutoFollowPatternRequest) {
+	return func(r *CCRResumeAutoFollowPatternRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.resume_follow.go b/esapi/api.xpack.ccr.resume_follow.go
new file mode 100644
index 0000000000..02c8b3b52b
--- /dev/null
+++ b/esapi/api.xpack.ccr.resume_follow.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newCCRResumeFollowFunc(t Transport) CCRResumeFollow {
+	return func(index string, o ...func(*CCRResumeFollowRequest)) (*Response, error) {
+		var r = CCRResumeFollowRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRResumeFollow - Resumes a follower index that has been paused
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-resume-follow.html.
+//
+type CCRResumeFollow func(index string, o ...func(*CCRResumeFollowRequest)) (*Response, error)
+
+// CCRResumeFollowRequest configures the CCR Resume Follow API request.
+//
+type CCRResumeFollowRequest struct {
+	Index string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRResumeFollowRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ccr") + 1 + len("resume_follow"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("resume_follow")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRResumeFollow) WithContext(v context.Context) func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The name of the leader index and other optional ccr related parameters.
+//
+func (f CCRResumeFollow) WithBody(v io.Reader) func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRResumeFollow) WithPretty() func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRResumeFollow) WithHuman() func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRResumeFollow) WithErrorTrace() func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRResumeFollow) WithFilterPath(v ...string) func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRResumeFollow) WithHeader(h map[string]string) func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRResumeFollow) WithOpaqueID(s string) func(*CCRResumeFollowRequest) {
+	return func(r *CCRResumeFollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.stats.go b/esapi/api.xpack.ccr.stats.go
new file mode 100644
index 0000000000..5235fcd599
--- /dev/null
+++ b/esapi/api.xpack.ccr.stats.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRStatsFunc(t Transport) CCRStats {
+	return func(o ...func(*CCRStatsRequest)) (*Response, error) {
+		var r = CCRStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRStats - Gets all stats related to cross-cluster replication.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-stats.html.
+//
+type CCRStats func(o ...func(*CCRStatsRequest)) (*Response, error)
+
+// CCRStatsRequest configures the CCR Stats API request.
+//
+type CCRStatsRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_ccr/stats"))
+	path.WriteString("/_ccr/stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRStats) WithContext(v context.Context) func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRStats) WithPretty() func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRStats) WithHuman() func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRStats) WithErrorTrace() func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRStats) WithFilterPath(v ...string) func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRStats) WithHeader(h map[string]string) func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRStats) WithOpaqueID(s string) func(*CCRStatsRequest) {
+	return func(r *CCRStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ccr.unfollow.go b/esapi/api.xpack.ccr.unfollow.go
new file mode 100644
index 0000000000..9b36658edb
--- /dev/null
+++ b/esapi/api.xpack.ccr.unfollow.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newCCRUnfollowFunc(t Transport) CCRUnfollow {
+	return func(index string, o ...func(*CCRUnfollowRequest)) (*Response, error) {
+		var r = CCRUnfollowRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// CCRUnfollow - Stops the following task associated with a follower index and removes index metadata and settings associated with cross-cluster replication.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-unfollow.html.
+//
+type CCRUnfollow func(index string, o ...func(*CCRUnfollowRequest)) (*Response, error)
+
+// CCRUnfollowRequest configures the CCR Unfollow API request.
+//
+type CCRUnfollowRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r CCRUnfollowRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ccr") + 1 + len("unfollow"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ccr")
+	path.WriteString("/")
+	path.WriteString("unfollow")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f CCRUnfollow) WithContext(v context.Context) func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f CCRUnfollow) WithPretty() func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f CCRUnfollow) WithHuman() func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f CCRUnfollow) WithErrorTrace() func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f CCRUnfollow) WithFilterPath(v ...string) func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f CCRUnfollow) WithHeader(h map[string]string) func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f CCRUnfollow) WithOpaqueID(s string) func(*CCRUnfollowRequest) {
+	return func(r *CCRUnfollowRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.close_point_in_time.go b/esapi/api.xpack.close_point_in_time.go
new file mode 100644
index 0000000000..65531c5f0d
--- /dev/null
+++ b/esapi/api.xpack.close_point_in_time.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newClosePointInTimeFunc(t Transport) ClosePointInTime {
+	return func(o ...func(*ClosePointInTimeRequest)) (*Response, error) {
+		var r = ClosePointInTimeRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ClosePointInTime - Close a point in time
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/point-in-time-api.html.
+//
+type ClosePointInTime func(o ...func(*ClosePointInTimeRequest)) (*Response, error)
+
+// ClosePointInTimeRequest configures the Close Point In Time API request.
+//
+type ClosePointInTimeRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ClosePointInTimeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(len("/_pit"))
+	path.WriteString("/_pit")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ClosePointInTime) WithContext(v context.Context) func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - a point-in-time id to close.
+//
+func (f ClosePointInTime) WithBody(v io.Reader) func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ClosePointInTime) WithPretty() func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ClosePointInTime) WithHuman() func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ClosePointInTime) WithErrorTrace() func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ClosePointInTime) WithFilterPath(v ...string) func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ClosePointInTime) WithHeader(h map[string]string) func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ClosePointInTime) WithOpaqueID(s string) func(*ClosePointInTimeRequest) {
+	return func(r *ClosePointInTimeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.delete_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.delete_transform.go
new file mode 100644
index 0000000000..69a50a6b16
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.delete_transform.go
@@ -0,0 +1,220 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedDeleteTransformFunc(t Transport) DataFrameTransformDeprecatedDeleteTransform {
+	return func(transform_id string, o ...func(*DataFrameTransformDeprecatedDeleteTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedDeleteTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedDeleteTransform - Deletes an existing transform.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-transform.html.
+//
+type DataFrameTransformDeprecatedDeleteTransform func(transform_id string, o ...func(*DataFrameTransformDeprecatedDeleteTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedDeleteTransformRequest configures the Data Frame Transform Deprecated Delete Transform API request.
+//
+type DataFrameTransformDeprecatedDeleteTransformRequest struct {
+	TransformID string
+
+	Force *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedDeleteTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+
+	params = make(map[string]string)
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForce - when `true`, the transform is deleted regardless of its current state. the default value is `false`, meaning that the transform must be `stopped` before it can be deleted..
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithForce(v bool) func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.Force = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithPretty() func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithHuman() func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedDeleteTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedDeleteTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedDeleteTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.get_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.get_transform.go
new file mode 100644
index 0000000000..99c37a23fa
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.get_transform.go
@@ -0,0 +1,269 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedGetTransformFunc(t Transport) DataFrameTransformDeprecatedGetTransform {
+	return func(o ...func(*DataFrameTransformDeprecatedGetTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedGetTransformRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedGetTransform - Retrieves configuration information for transforms.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-transform.html.
+//
+type DataFrameTransformDeprecatedGetTransform func(o ...func(*DataFrameTransformDeprecatedGetTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedGetTransformRequest configures the Data Frame Transform Deprecated Get Transform API request.
+//
+type DataFrameTransformDeprecatedGetTransformRequest struct {
+	TransformID string
+
+	AllowNoMatch     *bool
+	ExcludeGenerated *bool
+	From             *int
+	Size             *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedGetTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	if r.TransformID != "" {
+		path.WriteString("/")
+		path.WriteString(r.TransformID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTransformID - the ID or comma delimited list of ID expressions of the transforms to get, '_all' or '*' implies get all transforms.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithTransformID(v string) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.TransformID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithAllowNoMatch(v bool) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithExcludeGenerated - omits generated fields. allows transform configurations to be easily copied between clusters and within the same cluster.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithExcludeGenerated(v bool) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithFrom - skips a number of transform configs, defaults to 0.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithFrom(v int) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of transforms to get, defaults to 100.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithSize(v int) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithPretty() func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithHuman() func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedGetTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedGetTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.get_transform_stats.go b/esapi/api.xpack.data_frame_transform_deprecated.get_transform_stats.go
new file mode 100644
index 0000000000..4ad66cef1a
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.get_transform_stats.go
@@ -0,0 +1,248 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedGetTransformStatsFunc(t Transport) DataFrameTransformDeprecatedGetTransformStats {
+	return func(transform_id string, o ...func(*DataFrameTransformDeprecatedGetTransformStatsRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedGetTransformStatsRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedGetTransformStats - Retrieves usage information for transforms.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-transform-stats.html.
+//
+type DataFrameTransformDeprecatedGetTransformStats func(transform_id string, o ...func(*DataFrameTransformDeprecatedGetTransformStatsRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedGetTransformStatsRequest configures the Data Frame Transform Deprecated Get Transform Stats API request.
+//
+type DataFrameTransformDeprecatedGetTransformStatsRequest struct {
+	TransformID string
+
+	AllowNoMatch *bool
+	From         *int
+	Size         *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedGetTransformStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithContext(v context.Context) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithAllowNoMatch(v bool) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFrom - skips a number of transform stats, defaults to 0.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithFrom(v int) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of transform stats to get, defaults to 100.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithSize(v int) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithPretty() func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithHuman() func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithErrorTrace() func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedGetTransformStats) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedGetTransformStatsRequest) {
+	return func(r *DataFrameTransformDeprecatedGetTransformStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.preview_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.preview_transform.go
new file mode 100644
index 0000000000..d48281a812
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.preview_transform.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedPreviewTransformFunc(t Transport) DataFrameTransformDeprecatedPreviewTransform {
+	return func(body io.Reader, o ...func(*DataFrameTransformDeprecatedPreviewTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedPreviewTransformRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedPreviewTransform - Previews a transform.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/preview-transform.html.
+//
+type DataFrameTransformDeprecatedPreviewTransform func(body io.Reader, o ...func(*DataFrameTransformDeprecatedPreviewTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedPreviewTransformRequest configures the Data Frame Transform Deprecated Preview Transform API request.
+//
+type DataFrameTransformDeprecatedPreviewTransformRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedPreviewTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_data_frame/transforms/_preview"))
+	path.WriteString("/_data_frame/transforms/_preview")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithPretty() func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithHuman() func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedPreviewTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedPreviewTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPreviewTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.put_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.put_transform.go
new file mode 100644
index 0000000000..6f1acd7a5a
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.put_transform.go
@@ -0,0 +1,227 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedPutTransformFunc(t Transport) DataFrameTransformDeprecatedPutTransform {
+	return func(body io.Reader, transform_id string, o ...func(*DataFrameTransformDeprecatedPutTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedPutTransformRequest{Body: body, TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedPutTransform - Instantiates a transform.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-transform.html.
+//
+type DataFrameTransformDeprecatedPutTransform func(body io.Reader, transform_id string, o ...func(*DataFrameTransformDeprecatedPutTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedPutTransformRequest configures the Data Frame Transform Deprecated Put Transform API request.
+//
+type DataFrameTransformDeprecatedPutTransformRequest struct {
+	Body io.Reader
+
+	TransformID string
+
+	DeferValidation *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedPutTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+
+	params = make(map[string]string)
+
+	if r.DeferValidation != nil {
+		params["defer_validation"] = strconv.FormatBool(*r.DeferValidation)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDeferValidation - if validations should be deferred until transform starts, defaults to false..
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithDeferValidation(v bool) func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.DeferValidation = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithPretty() func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithHuman() func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedPutTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedPutTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedPutTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.start_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.start_transform.go
new file mode 100644
index 0000000000..2c0c5b4437
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.start_transform.go
@@ -0,0 +1,222 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newDataFrameTransformDeprecatedStartTransformFunc(t Transport) DataFrameTransformDeprecatedStartTransform {
+	return func(transform_id string, o ...func(*DataFrameTransformDeprecatedStartTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedStartTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedStartTransform - Starts one or more transforms.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/start-transform.html.
+//
+type DataFrameTransformDeprecatedStartTransform func(transform_id string, o ...func(*DataFrameTransformDeprecatedStartTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedStartTransformRequest configures the Data Frame Transform Deprecated Start Transform API request.
+//
+type DataFrameTransformDeprecatedStartTransformRequest struct {
+	TransformID string
+
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedStartTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID) + 1 + len("_start"))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_start")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTimeout - controls the time to wait for the transform to start.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithTimeout(v time.Duration) func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithPretty() func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithHuman() func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedStartTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedStartTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStartTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.stop_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.stop_transform.go
new file mode 100644
index 0000000000..5fa4f47b8a
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.stop_transform.go
@@ -0,0 +1,249 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newDataFrameTransformDeprecatedStopTransformFunc(t Transport) DataFrameTransformDeprecatedStopTransform {
+	return func(transform_id string, o ...func(*DataFrameTransformDeprecatedStopTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedStopTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedStopTransform - Stops one or more transforms.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/stop-transform.html.
+//
+type DataFrameTransformDeprecatedStopTransform func(transform_id string, o ...func(*DataFrameTransformDeprecatedStopTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedStopTransformRequest configures the Data Frame Transform Deprecated Stop Transform API request.
+//
+type DataFrameTransformDeprecatedStopTransformRequest struct {
+	TransformID string
+
+	AllowNoMatch      *bool
+	Timeout           time.Duration
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedStopTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID) + 1 + len("_stop"))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_stop")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithAllowNoMatch(v bool) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until the transform has stopped. default to 30 seconds.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithTimeout(v time.Duration) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForCompletion - whether to wait for the transform to fully stop before returning or not. default to false.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithWaitForCompletion(v bool) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithPretty() func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithHuman() func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedStopTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedStopTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedStopTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.data_frame_transform_deprecated.update_transform.go b/esapi/api.xpack.data_frame_transform_deprecated.update_transform.go
new file mode 100644
index 0000000000..53c619e044
--- /dev/null
+++ b/esapi/api.xpack.data_frame_transform_deprecated.update_transform.go
@@ -0,0 +1,229 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newDataFrameTransformDeprecatedUpdateTransformFunc(t Transport) DataFrameTransformDeprecatedUpdateTransform {
+	return func(body io.Reader, transform_id string, o ...func(*DataFrameTransformDeprecatedUpdateTransformRequest)) (*Response, error) {
+		var r = DataFrameTransformDeprecatedUpdateTransformRequest{Body: body, TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// DataFrameTransformDeprecatedUpdateTransform - Updates certain properties of a transform.
+//
+// This API is beta.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/update-transform.html.
+//
+type DataFrameTransformDeprecatedUpdateTransform func(body io.Reader, transform_id string, o ...func(*DataFrameTransformDeprecatedUpdateTransformRequest)) (*Response, error)
+
+// DataFrameTransformDeprecatedUpdateTransformRequest configures the Data Frame Transform Deprecated Update Transform API request.
+//
+type DataFrameTransformDeprecatedUpdateTransformRequest struct {
+	Body io.Reader
+
+	TransformID string
+
+	DeferValidation *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r DataFrameTransformDeprecatedUpdateTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_data_frame") + 1 + len("transforms") + 1 + len(r.TransformID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_data_frame")
+	path.WriteString("/")
+	path.WriteString("transforms")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.DeferValidation != nil {
+		params["defer_validation"] = strconv.FormatBool(*r.DeferValidation)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithContext(v context.Context) func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDeferValidation - if validations should be deferred until transform starts, defaults to false..
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithDeferValidation(v bool) func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.DeferValidation = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithPretty() func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithHuman() func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithErrorTrace() func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithFilterPath(v ...string) func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithHeader(h map[string]string) func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f DataFrameTransformDeprecatedUpdateTransform) WithOpaqueID(s string) func(*DataFrameTransformDeprecatedUpdateTransformRequest) {
+	return func(r *DataFrameTransformDeprecatedUpdateTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.enrich.delete_policy.go b/esapi/api.xpack.enrich.delete_policy.go
new file mode 100644
index 0000000000..5ff07d69b7
--- /dev/null
+++ b/esapi/api.xpack.enrich.delete_policy.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newEnrichDeletePolicyFunc(t Transport) EnrichDeletePolicy {
+	return func(name string, o ...func(*EnrichDeletePolicyRequest)) (*Response, error) {
+		var r = EnrichDeletePolicyRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EnrichDeletePolicy - Deletes an existing enrich policy and its enrich index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-enrich-policy-api.html.
+//
+type EnrichDeletePolicy func(name string, o ...func(*EnrichDeletePolicyRequest)) (*Response, error)
+
+// EnrichDeletePolicyRequest configures the Enrich Delete Policy API request.
+//
+type EnrichDeletePolicyRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EnrichDeletePolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_enrich") + 1 + len("policy") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_enrich")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EnrichDeletePolicy) WithContext(v context.Context) func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EnrichDeletePolicy) WithPretty() func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EnrichDeletePolicy) WithHuman() func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EnrichDeletePolicy) WithErrorTrace() func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EnrichDeletePolicy) WithFilterPath(v ...string) func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EnrichDeletePolicy) WithHeader(h map[string]string) func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EnrichDeletePolicy) WithOpaqueID(s string) func(*EnrichDeletePolicyRequest) {
+	return func(r *EnrichDeletePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.enrich.execute_policy.go b/esapi/api.xpack.enrich.execute_policy.go
new file mode 100644
index 0000000000..206d7c7a9c
--- /dev/null
+++ b/esapi/api.xpack.enrich.execute_policy.go
@@ -0,0 +1,220 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newEnrichExecutePolicyFunc(t Transport) EnrichExecutePolicy {
+	return func(name string, o ...func(*EnrichExecutePolicyRequest)) (*Response, error) {
+		var r = EnrichExecutePolicyRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EnrichExecutePolicy - Creates the enrich index for an existing enrich policy.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/execute-enrich-policy-api.html.
+//
+type EnrichExecutePolicy func(name string, o ...func(*EnrichExecutePolicyRequest)) (*Response, error)
+
+// EnrichExecutePolicyRequest configures the Enrich Execute Policy API request.
+//
+type EnrichExecutePolicyRequest struct {
+	Name string
+
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EnrichExecutePolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_enrich") + 1 + len("policy") + 1 + len(r.Name) + 1 + len("_execute"))
+	path.WriteString("/")
+	path.WriteString("_enrich")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+	path.WriteString("/")
+	path.WriteString("_execute")
+
+	params = make(map[string]string)
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EnrichExecutePolicy) WithContext(v context.Context) func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithWaitForCompletion - should the request should block until the execution is complete..
+//
+func (f EnrichExecutePolicy) WithWaitForCompletion(v bool) func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EnrichExecutePolicy) WithPretty() func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EnrichExecutePolicy) WithHuman() func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EnrichExecutePolicy) WithErrorTrace() func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EnrichExecutePolicy) WithFilterPath(v ...string) func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EnrichExecutePolicy) WithHeader(h map[string]string) func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EnrichExecutePolicy) WithOpaqueID(s string) func(*EnrichExecutePolicyRequest) {
+	return func(r *EnrichExecutePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.enrich.get_policy.go b/esapi/api.xpack.enrich.get_policy.go
new file mode 100644
index 0000000000..5918403f11
--- /dev/null
+++ b/esapi/api.xpack.enrich.get_policy.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newEnrichGetPolicyFunc(t Transport) EnrichGetPolicy {
+	return func(o ...func(*EnrichGetPolicyRequest)) (*Response, error) {
+		var r = EnrichGetPolicyRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EnrichGetPolicy - Gets information about an enrich policy.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-enrich-policy-api.html.
+//
+type EnrichGetPolicy func(o ...func(*EnrichGetPolicyRequest)) (*Response, error)
+
+// EnrichGetPolicyRequest configures the Enrich Get Policy API request.
+//
+type EnrichGetPolicyRequest struct {
+	Name []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EnrichGetPolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_enrich") + 1 + len("policy") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_enrich")
+	path.WriteString("/")
+	path.WriteString("policy")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EnrichGetPolicy) WithContext(v context.Context) func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a list of enrich policy names.
+//
+func (f EnrichGetPolicy) WithName(v ...string) func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EnrichGetPolicy) WithPretty() func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EnrichGetPolicy) WithHuman() func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EnrichGetPolicy) WithErrorTrace() func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EnrichGetPolicy) WithFilterPath(v ...string) func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EnrichGetPolicy) WithHeader(h map[string]string) func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EnrichGetPolicy) WithOpaqueID(s string) func(*EnrichGetPolicyRequest) {
+	return func(r *EnrichGetPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.enrich.put_policy.go b/esapi/api.xpack.enrich.put_policy.go
new file mode 100644
index 0000000000..2765c1782b
--- /dev/null
+++ b/esapi/api.xpack.enrich.put_policy.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newEnrichPutPolicyFunc(t Transport) EnrichPutPolicy {
+	return func(name string, body io.Reader, o ...func(*EnrichPutPolicyRequest)) (*Response, error) {
+		var r = EnrichPutPolicyRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EnrichPutPolicy - Creates a new enrich policy.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-enrich-policy-api.html.
+//
+type EnrichPutPolicy func(name string, body io.Reader, o ...func(*EnrichPutPolicyRequest)) (*Response, error)
+
+// EnrichPutPolicyRequest configures the Enrich Put Policy API request.
+//
+type EnrichPutPolicyRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EnrichPutPolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_enrich") + 1 + len("policy") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_enrich")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EnrichPutPolicy) WithContext(v context.Context) func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EnrichPutPolicy) WithPretty() func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EnrichPutPolicy) WithHuman() func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EnrichPutPolicy) WithErrorTrace() func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EnrichPutPolicy) WithFilterPath(v ...string) func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EnrichPutPolicy) WithHeader(h map[string]string) func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EnrichPutPolicy) WithOpaqueID(s string) func(*EnrichPutPolicyRequest) {
+	return func(r *EnrichPutPolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.enrich.stats.go b/esapi/api.xpack.enrich.stats.go
new file mode 100644
index 0000000000..f3b0e4d324
--- /dev/null
+++ b/esapi/api.xpack.enrich.stats.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newEnrichStatsFunc(t Transport) EnrichStats {
+	return func(o ...func(*EnrichStatsRequest)) (*Response, error) {
+		var r = EnrichStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EnrichStats - Gets enrich coordinator statistics and information about enrich policies that are currently executing.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-stats-api.html.
+//
+type EnrichStats func(o ...func(*EnrichStatsRequest)) (*Response, error)
+
+// EnrichStatsRequest configures the Enrich Stats API request.
+//
+type EnrichStatsRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EnrichStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_enrich/_stats"))
+	path.WriteString("/_enrich/_stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EnrichStats) WithContext(v context.Context) func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EnrichStats) WithPretty() func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EnrichStats) WithHuman() func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EnrichStats) WithErrorTrace() func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EnrichStats) WithFilterPath(v ...string) func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EnrichStats) WithHeader(h map[string]string) func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EnrichStats) WithOpaqueID(s string) func(*EnrichStatsRequest) {
+	return func(r *EnrichStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.eql.delete.go b/esapi/api.xpack.eql.delete.go
new file mode 100644
index 0000000000..9ea1f7e362
--- /dev/null
+++ b/esapi/api.xpack.eql.delete.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newEqlDeleteFunc(t Transport) EqlDelete {
+	return func(id string, o ...func(*EqlDeleteRequest)) (*Response, error) {
+		var r = EqlDeleteRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EqlDelete - Deletes an async EQL search by ID. If the search is still running, the search request will be cancelled. Otherwise, the saved search results are deleted.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html.
+//
+type EqlDelete func(id string, o ...func(*EqlDeleteRequest)) (*Response, error)
+
+// EqlDeleteRequest configures the Eql Delete API request.
+//
+type EqlDeleteRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EqlDeleteRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_eql") + 1 + len("search") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_eql")
+	path.WriteString("/")
+	path.WriteString("search")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EqlDelete) WithContext(v context.Context) func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EqlDelete) WithPretty() func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EqlDelete) WithHuman() func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EqlDelete) WithErrorTrace() func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EqlDelete) WithFilterPath(v ...string) func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EqlDelete) WithHeader(h map[string]string) func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EqlDelete) WithOpaqueID(s string) func(*EqlDeleteRequest) {
+	return func(r *EqlDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.eql.get.go b/esapi/api.xpack.eql.get.go
new file mode 100644
index 0000000000..2c515624b0
--- /dev/null
+++ b/esapi/api.xpack.eql.get.go
@@ -0,0 +1,231 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newEqlGetFunc(t Transport) EqlGet {
+	return func(id string, o ...func(*EqlGetRequest)) (*Response, error) {
+		var r = EqlGetRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EqlGet - Returns async results from previously executed Event Query Language (EQL) search
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html.
+//
+type EqlGet func(id string, o ...func(*EqlGetRequest)) (*Response, error)
+
+// EqlGetRequest configures the Eql Get API request.
+//
+type EqlGetRequest struct {
+	DocumentID string
+
+	KeepAlive                time.Duration
+	WaitForCompletionTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EqlGetRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_eql") + 1 + len("search") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_eql")
+	path.WriteString("/")
+	path.WriteString("search")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.KeepAlive != 0 {
+		params["keep_alive"] = formatDuration(r.KeepAlive)
+	}
+
+	if r.WaitForCompletionTimeout != 0 {
+		params["wait_for_completion_timeout"] = formatDuration(r.WaitForCompletionTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EqlGet) WithContext(v context.Context) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.ctx = v
+	}
+}
+
+// WithKeepAlive - update the time interval in which the results (partial or final) for this search will be available.
+//
+func (f EqlGet) WithKeepAlive(v time.Duration) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithWaitForCompletionTimeout - specify the time that the request should block waiting for the final response.
+//
+func (f EqlGet) WithWaitForCompletionTimeout(v time.Duration) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.WaitForCompletionTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EqlGet) WithPretty() func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EqlGet) WithHuman() func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EqlGet) WithErrorTrace() func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EqlGet) WithFilterPath(v ...string) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EqlGet) WithHeader(h map[string]string) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EqlGet) WithOpaqueID(s string) func(*EqlGetRequest) {
+	return func(r *EqlGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.eql.get_status.go b/esapi/api.xpack.eql.get_status.go
new file mode 100644
index 0000000000..e7dd577030
--- /dev/null
+++ b/esapi/api.xpack.eql.get_status.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newEqlGetStatusFunc(t Transport) EqlGetStatus {
+	return func(id string, o ...func(*EqlGetStatusRequest)) (*Response, error) {
+		var r = EqlGetStatusRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EqlGetStatus - Returns the status of a previously submitted async or stored Event Query Language (EQL) search
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html.
+//
+type EqlGetStatus func(id string, o ...func(*EqlGetStatusRequest)) (*Response, error)
+
+// EqlGetStatusRequest configures the Eql Get Status API request.
+//
+type EqlGetStatusRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EqlGetStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_eql") + 1 + len("search") + 1 + len("status") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_eql")
+	path.WriteString("/")
+	path.WriteString("search")
+	path.WriteString("/")
+	path.WriteString("status")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EqlGetStatus) WithContext(v context.Context) func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EqlGetStatus) WithPretty() func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EqlGetStatus) WithHuman() func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EqlGetStatus) WithErrorTrace() func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EqlGetStatus) WithFilterPath(v ...string) func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EqlGetStatus) WithHeader(h map[string]string) func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EqlGetStatus) WithOpaqueID(s string) func(*EqlGetStatusRequest) {
+	return func(r *EqlGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.eql.search.go b/esapi/api.xpack.eql.search.go
new file mode 100644
index 0000000000..02b5bf9580
--- /dev/null
+++ b/esapi/api.xpack.eql.search.go
@@ -0,0 +1,252 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newEqlSearchFunc(t Transport) EqlSearch {
+	return func(index string, body io.Reader, o ...func(*EqlSearchRequest)) (*Response, error) {
+		var r = EqlSearchRequest{Index: index, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// EqlSearch - Returns results matching a query expressed in Event Query Language (EQL)
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-search-api.html.
+//
+type EqlSearch func(index string, body io.Reader, o ...func(*EqlSearchRequest)) (*Response, error)
+
+// EqlSearchRequest configures the Eql Search API request.
+//
+type EqlSearchRequest struct {
+	Index string
+
+	Body io.Reader
+
+	KeepAlive                time.Duration
+	KeepOnCompletion         *bool
+	WaitForCompletionTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r EqlSearchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_eql") + 1 + len("search"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_eql")
+	path.WriteString("/")
+	path.WriteString("search")
+
+	params = make(map[string]string)
+
+	if r.KeepAlive != 0 {
+		params["keep_alive"] = formatDuration(r.KeepAlive)
+	}
+
+	if r.KeepOnCompletion != nil {
+		params["keep_on_completion"] = strconv.FormatBool(*r.KeepOnCompletion)
+	}
+
+	if r.WaitForCompletionTimeout != 0 {
+		params["wait_for_completion_timeout"] = formatDuration(r.WaitForCompletionTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f EqlSearch) WithContext(v context.Context) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithKeepAlive - update the time interval in which the results (partial or final) for this search will be available.
+//
+func (f EqlSearch) WithKeepAlive(v time.Duration) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithKeepOnCompletion - control whether the response should be stored in the cluster if it completed within the provided [wait_for_completion] time (default: false).
+//
+func (f EqlSearch) WithKeepOnCompletion(v bool) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.KeepOnCompletion = &v
+	}
+}
+
+// WithWaitForCompletionTimeout - specify the time that the request should block waiting for the final response.
+//
+func (f EqlSearch) WithWaitForCompletionTimeout(v time.Duration) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.WaitForCompletionTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f EqlSearch) WithPretty() func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f EqlSearch) WithHuman() func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f EqlSearch) WithErrorTrace() func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f EqlSearch) WithFilterPath(v ...string) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f EqlSearch) WithHeader(h map[string]string) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f EqlSearch) WithOpaqueID(s string) func(*EqlSearchRequest) {
+	return func(r *EqlSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.graph.explore.go b/esapi/api.xpack.graph.explore.go
new file mode 100644
index 0000000000..8228f3841f
--- /dev/null
+++ b/esapi/api.xpack.graph.explore.go
@@ -0,0 +1,259 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newGraphExploreFunc(t Transport) GraphExplore {
+	return func(index []string, o ...func(*GraphExploreRequest)) (*Response, error) {
+		var r = GraphExploreRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// GraphExplore - Explore extracted and summarized information about the documents and terms in an index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/graph-explore-api.html.
+//
+type GraphExplore func(index []string, o ...func(*GraphExploreRequest)) (*Response, error)
+
+// GraphExploreRequest configures the Graph Explore API request.
+//
+type GraphExploreRequest struct {
+	Index        []string
+	DocumentType []string
+
+	Body io.Reader
+
+	Routing string
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r GraphExploreRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(strings.Join(r.DocumentType, ",")) + 1 + len("_graph") + 1 + len("explore"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	if len(r.DocumentType) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.DocumentType, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("_graph")
+	path.WriteString("/")
+	path.WriteString("explore")
+
+	params = make(map[string]string)
+
+	if r.Routing != "" {
+		params["routing"] = r.Routing
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f GraphExplore) WithContext(v context.Context) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Graph Query DSL.
+//
+func (f GraphExplore) WithBody(v io.Reader) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.Body = v
+	}
+}
+
+// WithDocumentType - a list of document types to search; leave empty to perform the operation on all types.
+//
+func (f GraphExplore) WithDocumentType(v ...string) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.DocumentType = v
+	}
+}
+
+// WithRouting - specific routing value.
+//
+func (f GraphExplore) WithRouting(v string) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.Routing = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f GraphExplore) WithTimeout(v time.Duration) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f GraphExplore) WithPretty() func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f GraphExplore) WithHuman() func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f GraphExplore) WithErrorTrace() func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f GraphExplore) WithFilterPath(v ...string) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f GraphExplore) WithHeader(h map[string]string) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f GraphExplore) WithOpaqueID(s string) func(*GraphExploreRequest) {
+	return func(r *GraphExploreRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.delete_lifecycle.go b/esapi/api.xpack.ilm.delete_lifecycle.go
new file mode 100644
index 0000000000..01277dcf93
--- /dev/null
+++ b/esapi/api.xpack.ilm.delete_lifecycle.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMDeleteLifecycleFunc(t Transport) ILMDeleteLifecycle {
+	return func(policy string, o ...func(*ILMDeleteLifecycleRequest)) (*Response, error) {
+		var r = ILMDeleteLifecycleRequest{Policy: policy}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMDeleteLifecycle - Deletes the specified lifecycle policy definition. A currently used policy cannot be deleted.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-delete-lifecycle.html.
+//
+type ILMDeleteLifecycle func(policy string, o ...func(*ILMDeleteLifecycleRequest)) (*Response, error)
+
+// ILMDeleteLifecycleRequest configures the ILM Delete Lifecycle API request.
+//
+type ILMDeleteLifecycleRequest struct {
+	Policy string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMDeleteLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ilm") + 1 + len("policy") + 1 + len(r.Policy))
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Policy)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMDeleteLifecycle) WithContext(v context.Context) func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMDeleteLifecycle) WithPretty() func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMDeleteLifecycle) WithHuman() func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMDeleteLifecycle) WithErrorTrace() func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMDeleteLifecycle) WithFilterPath(v ...string) func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMDeleteLifecycle) WithHeader(h map[string]string) func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMDeleteLifecycle) WithOpaqueID(s string) func(*ILMDeleteLifecycleRequest) {
+	return func(r *ILMDeleteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.explain_lifecycle.go b/esapi/api.xpack.ilm.explain_lifecycle.go
new file mode 100644
index 0000000000..2baa03ae38
--- /dev/null
+++ b/esapi/api.xpack.ilm.explain_lifecycle.go
@@ -0,0 +1,231 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newILMExplainLifecycleFunc(t Transport) ILMExplainLifecycle {
+	return func(index string, o ...func(*ILMExplainLifecycleRequest)) (*Response, error) {
+		var r = ILMExplainLifecycleRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMExplainLifecycle - Retrieves information about the index's current lifecycle state, such as the currently executing phase, action, and step.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-explain-lifecycle.html.
+//
+type ILMExplainLifecycle func(index string, o ...func(*ILMExplainLifecycleRequest)) (*Response, error)
+
+// ILMExplainLifecycleRequest configures the ILM Explain Lifecycle API request.
+//
+type ILMExplainLifecycleRequest struct {
+	Index string
+
+	OnlyErrors  *bool
+	OnlyManaged *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMExplainLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ilm") + 1 + len("explain"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("explain")
+
+	params = make(map[string]string)
+
+	if r.OnlyErrors != nil {
+		params["only_errors"] = strconv.FormatBool(*r.OnlyErrors)
+	}
+
+	if r.OnlyManaged != nil {
+		params["only_managed"] = strconv.FormatBool(*r.OnlyManaged)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMExplainLifecycle) WithContext(v context.Context) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithOnlyErrors - filters the indices included in the response to ones in an ilm error state, implies only_managed.
+//
+func (f ILMExplainLifecycle) WithOnlyErrors(v bool) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.OnlyErrors = &v
+	}
+}
+
+// WithOnlyManaged - filters the indices included in the response to ones managed by ilm.
+//
+func (f ILMExplainLifecycle) WithOnlyManaged(v bool) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.OnlyManaged = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMExplainLifecycle) WithPretty() func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMExplainLifecycle) WithHuman() func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMExplainLifecycle) WithErrorTrace() func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMExplainLifecycle) WithFilterPath(v ...string) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMExplainLifecycle) WithHeader(h map[string]string) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMExplainLifecycle) WithOpaqueID(s string) func(*ILMExplainLifecycleRequest) {
+	return func(r *ILMExplainLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.get_lifecycle.go b/esapi/api.xpack.ilm.get_lifecycle.go
new file mode 100644
index 0000000000..5f8e0c434f
--- /dev/null
+++ b/esapi/api.xpack.ilm.get_lifecycle.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMGetLifecycleFunc(t Transport) ILMGetLifecycle {
+	return func(o ...func(*ILMGetLifecycleRequest)) (*Response, error) {
+		var r = ILMGetLifecycleRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMGetLifecycle - Returns the specified policy definition. Includes the policy version and last modified date.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-get-lifecycle.html.
+//
+type ILMGetLifecycle func(o ...func(*ILMGetLifecycleRequest)) (*Response, error)
+
+// ILMGetLifecycleRequest configures the ILM Get Lifecycle API request.
+//
+type ILMGetLifecycleRequest struct {
+	Policy string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMGetLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ilm") + 1 + len("policy") + 1 + len(r.Policy))
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	if r.Policy != "" {
+		path.WriteString("/")
+		path.WriteString(r.Policy)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMGetLifecycle) WithContext(v context.Context) func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPolicy - the name of the index lifecycle policy.
+//
+func (f ILMGetLifecycle) WithPolicy(v string) func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.Policy = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMGetLifecycle) WithPretty() func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMGetLifecycle) WithHuman() func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMGetLifecycle) WithErrorTrace() func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMGetLifecycle) WithFilterPath(v ...string) func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMGetLifecycle) WithHeader(h map[string]string) func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMGetLifecycle) WithOpaqueID(s string) func(*ILMGetLifecycleRequest) {
+	return func(r *ILMGetLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.get_status.go b/esapi/api.xpack.ilm.get_status.go
new file mode 100644
index 0000000000..70930d498f
--- /dev/null
+++ b/esapi/api.xpack.ilm.get_status.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMGetStatusFunc(t Transport) ILMGetStatus {
+	return func(o ...func(*ILMGetStatusRequest)) (*Response, error) {
+		var r = ILMGetStatusRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMGetStatus - Retrieves the current index lifecycle management (ILM) status.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-get-status.html.
+//
+type ILMGetStatus func(o ...func(*ILMGetStatusRequest)) (*Response, error)
+
+// ILMGetStatusRequest configures the ILM Get Status API request.
+//
+type ILMGetStatusRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMGetStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_ilm/status"))
+	path.WriteString("/_ilm/status")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMGetStatus) WithContext(v context.Context) func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMGetStatus) WithPretty() func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMGetStatus) WithHuman() func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMGetStatus) WithErrorTrace() func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMGetStatus) WithFilterPath(v ...string) func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMGetStatus) WithHeader(h map[string]string) func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMGetStatus) WithOpaqueID(s string) func(*ILMGetStatusRequest) {
+	return func(r *ILMGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.migrate_to_data_tiers.go b/esapi/api.xpack.ilm.migrate_to_data_tiers.go
new file mode 100644
index 0000000000..f9b39f9dc3
--- /dev/null
+++ b/esapi/api.xpack.ilm.migrate_to_data_tiers.go
@@ -0,0 +1,226 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newILMMigrateToDataTiersFunc(t Transport) ILMMigrateToDataTiers {
+	return func(o ...func(*ILMMigrateToDataTiersRequest)) (*Response, error) {
+		var r = ILMMigrateToDataTiersRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMMigrateToDataTiers - Migrates the indices and ILM policies away from custom node attribute allocation routing to data tiers routing
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-migrate-to-data-tiers.html.
+//
+type ILMMigrateToDataTiers func(o ...func(*ILMMigrateToDataTiersRequest)) (*Response, error)
+
+// ILMMigrateToDataTiersRequest configures the ILM Migrate To Data Tiers API request.
+//
+type ILMMigrateToDataTiersRequest struct {
+	Body io.Reader
+
+	DryRun *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMMigrateToDataTiersRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ilm/migrate_to_data_tiers"))
+	path.WriteString("/_ilm/migrate_to_data_tiers")
+
+	params = make(map[string]string)
+
+	if r.DryRun != nil {
+		params["dry_run"] = strconv.FormatBool(*r.DryRun)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMMigrateToDataTiers) WithContext(v context.Context) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Optionally specify a legacy index template name to delete and optionally specify a node attribute name used for index shard routing (defaults to "data").
+//
+func (f ILMMigrateToDataTiers) WithBody(v io.Reader) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.Body = v
+	}
+}
+
+// WithDryRun - if set to true it will simulate the migration, providing a way to retrieve the ilm policies and indices that need to be migrated. the default is false.
+//
+func (f ILMMigrateToDataTiers) WithDryRun(v bool) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.DryRun = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMMigrateToDataTiers) WithPretty() func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMMigrateToDataTiers) WithHuman() func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMMigrateToDataTiers) WithErrorTrace() func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMMigrateToDataTiers) WithFilterPath(v ...string) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMMigrateToDataTiers) WithHeader(h map[string]string) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMMigrateToDataTiers) WithOpaqueID(s string) func(*ILMMigrateToDataTiersRequest) {
+	return func(r *ILMMigrateToDataTiersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.move_to_step.go b/esapi/api.xpack.ilm.move_to_step.go
new file mode 100644
index 0000000000..52c00f5367
--- /dev/null
+++ b/esapi/api.xpack.ilm.move_to_step.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newILMMoveToStepFunc(t Transport) ILMMoveToStep {
+	return func(index string, o ...func(*ILMMoveToStepRequest)) (*Response, error) {
+		var r = ILMMoveToStepRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMMoveToStep - Manually moves an index into the specified step and executes that step.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-move-to-step.html.
+//
+type ILMMoveToStep func(index string, o ...func(*ILMMoveToStepRequest)) (*Response, error)
+
+// ILMMoveToStepRequest configures the ILM Move To Step API request.
+//
+type ILMMoveToStepRequest struct {
+	Index string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMMoveToStepRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ilm") + 1 + len("move") + 1 + len(r.Index))
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("move")
+	path.WriteString("/")
+	path.WriteString(r.Index)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMMoveToStep) WithContext(v context.Context) func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The new lifecycle step to move to.
+//
+func (f ILMMoveToStep) WithBody(v io.Reader) func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMMoveToStep) WithPretty() func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMMoveToStep) WithHuman() func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMMoveToStep) WithErrorTrace() func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMMoveToStep) WithFilterPath(v ...string) func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMMoveToStep) WithHeader(h map[string]string) func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMMoveToStep) WithOpaqueID(s string) func(*ILMMoveToStepRequest) {
+	return func(r *ILMMoveToStepRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.put_lifecycle.go b/esapi/api.xpack.ilm.put_lifecycle.go
new file mode 100644
index 0000000000..c1136832b1
--- /dev/null
+++ b/esapi/api.xpack.ilm.put_lifecycle.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newILMPutLifecycleFunc(t Transport) ILMPutLifecycle {
+	return func(policy string, o ...func(*ILMPutLifecycleRequest)) (*Response, error) {
+		var r = ILMPutLifecycleRequest{Policy: policy}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMPutLifecycle - Creates a lifecycle policy
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-put-lifecycle.html.
+//
+type ILMPutLifecycle func(policy string, o ...func(*ILMPutLifecycleRequest)) (*Response, error)
+
+// ILMPutLifecycleRequest configures the ILM Put Lifecycle API request.
+//
+type ILMPutLifecycleRequest struct {
+	Body io.Reader
+
+	Policy string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMPutLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ilm") + 1 + len("policy") + 1 + len(r.Policy))
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.Policy)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMPutLifecycle) WithContext(v context.Context) func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The lifecycle policy definition to register.
+//
+func (f ILMPutLifecycle) WithBody(v io.Reader) func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMPutLifecycle) WithPretty() func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMPutLifecycle) WithHuman() func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMPutLifecycle) WithErrorTrace() func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMPutLifecycle) WithFilterPath(v ...string) func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMPutLifecycle) WithHeader(h map[string]string) func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMPutLifecycle) WithOpaqueID(s string) func(*ILMPutLifecycleRequest) {
+	return func(r *ILMPutLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.remove_policy.go b/esapi/api.xpack.ilm.remove_policy.go
new file mode 100644
index 0000000000..7783549cec
--- /dev/null
+++ b/esapi/api.xpack.ilm.remove_policy.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMRemovePolicyFunc(t Transport) ILMRemovePolicy {
+	return func(index string, o ...func(*ILMRemovePolicyRequest)) (*Response, error) {
+		var r = ILMRemovePolicyRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMRemovePolicy - Removes the assigned lifecycle policy and stops managing the specified index
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-remove-policy.html.
+//
+type ILMRemovePolicy func(index string, o ...func(*ILMRemovePolicyRequest)) (*Response, error)
+
+// ILMRemovePolicyRequest configures the ILM Remove Policy API request.
+//
+type ILMRemovePolicyRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMRemovePolicyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ilm") + 1 + len("remove"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("remove")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMRemovePolicy) WithContext(v context.Context) func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMRemovePolicy) WithPretty() func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMRemovePolicy) WithHuman() func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMRemovePolicy) WithErrorTrace() func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMRemovePolicy) WithFilterPath(v ...string) func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMRemovePolicy) WithHeader(h map[string]string) func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMRemovePolicy) WithOpaqueID(s string) func(*ILMRemovePolicyRequest) {
+	return func(r *ILMRemovePolicyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.retry.go b/esapi/api.xpack.ilm.retry.go
new file mode 100644
index 0000000000..de1fb9b0d3
--- /dev/null
+++ b/esapi/api.xpack.ilm.retry.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMRetryFunc(t Transport) ILMRetry {
+	return func(index string, o ...func(*ILMRetryRequest)) (*Response, error) {
+		var r = ILMRetryRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMRetry - Retries executing the policy for an index that is in the ERROR step.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-retry-policy.html.
+//
+type ILMRetry func(index string, o ...func(*ILMRetryRequest)) (*Response, error)
+
+// ILMRetryRequest configures the ILM Retry API request.
+//
+type ILMRetryRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMRetryRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_ilm") + 1 + len("retry"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_ilm")
+	path.WriteString("/")
+	path.WriteString("retry")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMRetry) WithContext(v context.Context) func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMRetry) WithPretty() func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMRetry) WithHuman() func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMRetry) WithErrorTrace() func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMRetry) WithFilterPath(v ...string) func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMRetry) WithHeader(h map[string]string) func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMRetry) WithOpaqueID(s string) func(*ILMRetryRequest) {
+	return func(r *ILMRetryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.start.go b/esapi/api.xpack.ilm.start.go
new file mode 100644
index 0000000000..575cb57ed1
--- /dev/null
+++ b/esapi/api.xpack.ilm.start.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMStartFunc(t Transport) ILMStart {
+	return func(o ...func(*ILMStartRequest)) (*Response, error) {
+		var r = ILMStartRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMStart - Start the index lifecycle management (ILM) plugin.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-start.html.
+//
+type ILMStart func(o ...func(*ILMStartRequest)) (*Response, error)
+
+// ILMStartRequest configures the ILM Start API request.
+//
+type ILMStartRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMStartRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ilm/start"))
+	path.WriteString("/_ilm/start")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMStart) WithContext(v context.Context) func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMStart) WithPretty() func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMStart) WithHuman() func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMStart) WithErrorTrace() func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMStart) WithFilterPath(v ...string) func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMStart) WithHeader(h map[string]string) func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMStart) WithOpaqueID(s string) func(*ILMStartRequest) {
+	return func(r *ILMStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ilm.stop.go b/esapi/api.xpack.ilm.stop.go
new file mode 100644
index 0000000000..057a3c21fc
--- /dev/null
+++ b/esapi/api.xpack.ilm.stop.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newILMStopFunc(t Transport) ILMStop {
+	return func(o ...func(*ILMStopRequest)) (*Response, error) {
+		var r = ILMStopRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// ILMStop - Halts all lifecycle management operations and stops the index lifecycle management (ILM) plugin
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-stop.html.
+//
+type ILMStop func(o ...func(*ILMStopRequest)) (*Response, error)
+
+// ILMStopRequest configures the ILM Stop API request.
+//
+type ILMStopRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r ILMStopRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ilm/stop"))
+	path.WriteString("/_ilm/stop")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f ILMStop) WithContext(v context.Context) func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f ILMStop) WithPretty() func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f ILMStop) WithHuman() func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f ILMStop) WithErrorTrace() func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f ILMStop) WithFilterPath(v ...string) func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ILMStop) WithHeader(h map[string]string) func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ILMStop) WithOpaqueID(s string) func(*ILMStopRequest) {
+	return func(r *ILMStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.create_data_stream.go b/esapi/api.xpack.indices.create_data_stream.go
new file mode 100644
index 0000000000..37caeceda6
--- /dev/null
+++ b/esapi/api.xpack.indices.create_data_stream.go
@@ -0,0 +1,201 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesCreateDataStreamFunc(t Transport) IndicesCreateDataStream {
+	return func(name string, o ...func(*IndicesCreateDataStreamRequest)) (*Response, error) {
+		var r = IndicesCreateDataStreamRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesCreateDataStream - Creates a data stream
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesCreateDataStream func(name string, o ...func(*IndicesCreateDataStreamRequest)) (*Response, error)
+
+// IndicesCreateDataStreamRequest configures the Indices Create Data Stream API request.
+//
+type IndicesCreateDataStreamRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesCreateDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_data_stream") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesCreateDataStream) WithContext(v context.Context) func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesCreateDataStream) WithPretty() func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesCreateDataStream) WithHuman() func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesCreateDataStream) WithErrorTrace() func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesCreateDataStream) WithFilterPath(v ...string) func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesCreateDataStream) WithHeader(h map[string]string) func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesCreateDataStream) WithOpaqueID(s string) func(*IndicesCreateDataStreamRequest) {
+	return func(r *IndicesCreateDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.data_streams_stats.go b/esapi/api.xpack.indices.data_streams_stats.go
new file mode 100644
index 0000000000..f255150ac4
--- /dev/null
+++ b/esapi/api.xpack.indices.data_streams_stats.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesDataStreamsStatsFunc(t Transport) IndicesDataStreamsStats {
+	return func(o ...func(*IndicesDataStreamsStatsRequest)) (*Response, error) {
+		var r = IndicesDataStreamsStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesDataStreamsStats - Provides statistics on operations happening in a data stream.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesDataStreamsStats func(o ...func(*IndicesDataStreamsStatsRequest)) (*Response, error)
+
+// IndicesDataStreamsStatsRequest configures the Indices Data Streams Stats API request.
+//
+type IndicesDataStreamsStatsRequest struct {
+	Name []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesDataStreamsStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_data_stream") + 1 + len(strings.Join(r.Name, ",")) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesDataStreamsStats) WithContext(v context.Context) func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a list of data stream names; use _all to perform the operation on all data streams.
+//
+func (f IndicesDataStreamsStats) WithName(v ...string) func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesDataStreamsStats) WithPretty() func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesDataStreamsStats) WithHuman() func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesDataStreamsStats) WithErrorTrace() func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesDataStreamsStats) WithFilterPath(v ...string) func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDataStreamsStats) WithHeader(h map[string]string) func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDataStreamsStats) WithOpaqueID(s string) func(*IndicesDataStreamsStatsRequest) {
+	return func(r *IndicesDataStreamsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.delete_data_stream.go b/esapi/api.xpack.indices.delete_data_stream.go
new file mode 100644
index 0000000000..090bd1e67a
--- /dev/null
+++ b/esapi/api.xpack.indices.delete_data_stream.go
@@ -0,0 +1,215 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesDeleteDataStreamFunc(t Transport) IndicesDeleteDataStream {
+	return func(name []string, o ...func(*IndicesDeleteDataStreamRequest)) (*Response, error) {
+		var r = IndicesDeleteDataStreamRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesDeleteDataStream - Deletes a data stream.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesDeleteDataStream func(name []string, o ...func(*IndicesDeleteDataStreamRequest)) (*Response, error)
+
+// IndicesDeleteDataStreamRequest configures the Indices Delete Data Stream API request.
+//
+type IndicesDeleteDataStreamRequest struct {
+	Name []string
+
+	ExpandWildcards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesDeleteDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_data_stream") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Name, ","))
+
+	params = make(map[string]string)
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesDeleteDataStream) WithContext(v context.Context) func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithExpandWildcards - whether wildcard expressions should get expanded to open or closed indices (default: open).
+//
+func (f IndicesDeleteDataStream) WithExpandWildcards(v string) func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesDeleteDataStream) WithPretty() func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesDeleteDataStream) WithHuman() func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesDeleteDataStream) WithErrorTrace() func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesDeleteDataStream) WithFilterPath(v ...string) func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesDeleteDataStream) WithHeader(h map[string]string) func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesDeleteDataStream) WithOpaqueID(s string) func(*IndicesDeleteDataStreamRequest) {
+	return func(r *IndicesDeleteDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.freeze.go b/esapi/api.xpack.indices.freeze.go
new file mode 100644
index 0000000000..0f48731455
--- /dev/null
+++ b/esapi/api.xpack.indices.freeze.go
@@ -0,0 +1,282 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesFreezeFunc(t Transport) IndicesFreeze {
+	return func(index string, o ...func(*IndicesFreezeRequest)) (*Response, error) {
+		var r = IndicesFreezeRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesFreeze - Freezes an index. A frozen index has almost no overhead on the cluster (except for maintaining its metadata in memory) and is read-only.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/freeze-index-api.html.
+//
+type IndicesFreeze func(index string, o ...func(*IndicesFreezeRequest)) (*Response, error)
+
+// IndicesFreezeRequest configures the Indices Freeze API request.
+//
+type IndicesFreezeRequest struct {
+	Index string
+
+	AllowNoIndices      *bool
+	ExpandWildcards     string
+	IgnoreUnavailable   *bool
+	MasterTimeout       time.Duration
+	Timeout             time.Duration
+	WaitForActiveShards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesFreezeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_freeze"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_freeze")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForActiveShards != "" {
+		params["wait_for_active_shards"] = r.WaitForActiveShards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesFreeze) WithContext(v context.Context) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesFreeze) WithAllowNoIndices(v bool) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesFreeze) WithExpandWildcards(v string) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesFreeze) WithIgnoreUnavailable(v bool) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesFreeze) WithMasterTimeout(v time.Duration) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f IndicesFreeze) WithTimeout(v time.Duration) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForActiveShards - sets the number of active shards to wait for before the operation returns..
+//
+func (f IndicesFreeze) WithWaitForActiveShards(v string) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.WaitForActiveShards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesFreeze) WithPretty() func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesFreeze) WithHuman() func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesFreeze) WithErrorTrace() func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesFreeze) WithFilterPath(v ...string) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesFreeze) WithHeader(h map[string]string) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesFreeze) WithOpaqueID(s string) func(*IndicesFreezeRequest) {
+	return func(r *IndicesFreezeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.get_data_stream.go b/esapi/api.xpack.indices.get_data_stream.go
new file mode 100644
index 0000000000..a0212f1e1b
--- /dev/null
+++ b/esapi/api.xpack.indices.get_data_stream.go
@@ -0,0 +1,225 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesGetDataStreamFunc(t Transport) IndicesGetDataStream {
+	return func(o ...func(*IndicesGetDataStreamRequest)) (*Response, error) {
+		var r = IndicesGetDataStreamRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesGetDataStream - Returns data streams.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesGetDataStream func(o ...func(*IndicesGetDataStreamRequest)) (*Response, error)
+
+// IndicesGetDataStreamRequest configures the Indices Get Data Stream API request.
+//
+type IndicesGetDataStreamRequest struct {
+	Name []string
+
+	ExpandWildcards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesGetDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_data_stream") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesGetDataStream) WithContext(v context.Context) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a list of data streams to get; use `*` to get all data streams.
+//
+func (f IndicesGetDataStream) WithName(v ...string) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.Name = v
+	}
+}
+
+// WithExpandWildcards - whether wildcard expressions should get expanded to open or closed indices (default: open).
+//
+func (f IndicesGetDataStream) WithExpandWildcards(v string) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesGetDataStream) WithPretty() func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesGetDataStream) WithHuman() func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesGetDataStream) WithErrorTrace() func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesGetDataStream) WithFilterPath(v ...string) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesGetDataStream) WithHeader(h map[string]string) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesGetDataStream) WithOpaqueID(s string) func(*IndicesGetDataStreamRequest) {
+	return func(r *IndicesGetDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.migrate_to_data_stream.go b/esapi/api.xpack.indices.migrate_to_data_stream.go
new file mode 100644
index 0000000000..c6edc15f8d
--- /dev/null
+++ b/esapi/api.xpack.indices.migrate_to_data_stream.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesMigrateToDataStreamFunc(t Transport) IndicesMigrateToDataStream {
+	return func(name string, o ...func(*IndicesMigrateToDataStreamRequest)) (*Response, error) {
+		var r = IndicesMigrateToDataStreamRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesMigrateToDataStream - Migrates an alias to a data stream
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesMigrateToDataStream func(name string, o ...func(*IndicesMigrateToDataStreamRequest)) (*Response, error)
+
+// IndicesMigrateToDataStreamRequest configures the Indices Migrate To Data Stream API request.
+//
+type IndicesMigrateToDataStreamRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesMigrateToDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_data_stream") + 1 + len("_migrate") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	path.WriteString("/")
+	path.WriteString("_migrate")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesMigrateToDataStream) WithContext(v context.Context) func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesMigrateToDataStream) WithPretty() func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesMigrateToDataStream) WithHuman() func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesMigrateToDataStream) WithErrorTrace() func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesMigrateToDataStream) WithFilterPath(v ...string) func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesMigrateToDataStream) WithHeader(h map[string]string) func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesMigrateToDataStream) WithOpaqueID(s string) func(*IndicesMigrateToDataStreamRequest) {
+	return func(r *IndicesMigrateToDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.promote_data_stream.go b/esapi/api.xpack.indices.promote_data_stream.go
new file mode 100644
index 0000000000..ffb88486cd
--- /dev/null
+++ b/esapi/api.xpack.indices.promote_data_stream.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newIndicesPromoteDataStreamFunc(t Transport) IndicesPromoteDataStream {
+	return func(name string, o ...func(*IndicesPromoteDataStreamRequest)) (*Response, error) {
+		var r = IndicesPromoteDataStreamRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesPromoteDataStream - Promotes a data stream from a replicated data stream managed by CCR to a regular data stream
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/data-streams.html.
+//
+type IndicesPromoteDataStream func(name string, o ...func(*IndicesPromoteDataStreamRequest)) (*Response, error)
+
+// IndicesPromoteDataStreamRequest configures the Indices Promote Data Stream API request.
+//
+type IndicesPromoteDataStreamRequest struct {
+	Name string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesPromoteDataStreamRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_data_stream") + 1 + len("_promote") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_data_stream")
+	path.WriteString("/")
+	path.WriteString("_promote")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesPromoteDataStream) WithContext(v context.Context) func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesPromoteDataStream) WithPretty() func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesPromoteDataStream) WithHuman() func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesPromoteDataStream) WithErrorTrace() func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesPromoteDataStream) WithFilterPath(v ...string) func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesPromoteDataStream) WithHeader(h map[string]string) func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesPromoteDataStream) WithOpaqueID(s string) func(*IndicesPromoteDataStreamRequest) {
+	return func(r *IndicesPromoteDataStreamRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.reload_search_analyzers.go b/esapi/api.xpack.indices.reload_search_analyzers.go
new file mode 100644
index 0000000000..7178e48c55
--- /dev/null
+++ b/esapi/api.xpack.indices.reload_search_analyzers.go
@@ -0,0 +1,242 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newIndicesReloadSearchAnalyzersFunc(t Transport) IndicesReloadSearchAnalyzers {
+	return func(index []string, o ...func(*IndicesReloadSearchAnalyzersRequest)) (*Response, error) {
+		var r = IndicesReloadSearchAnalyzersRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesReloadSearchAnalyzers - Reloads an index's search analyzers and their resources.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-reload-analyzers.html.
+//
+type IndicesReloadSearchAnalyzers func(index []string, o ...func(*IndicesReloadSearchAnalyzersRequest)) (*Response, error)
+
+// IndicesReloadSearchAnalyzersRequest configures the Indices Reload Search Analyzers API request.
+//
+type IndicesReloadSearchAnalyzersRequest struct {
+	Index []string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesReloadSearchAnalyzersRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_reload_search_analyzers"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_reload_search_analyzers")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesReloadSearchAnalyzers) WithContext(v context.Context) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesReloadSearchAnalyzers) WithAllowNoIndices(v bool) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesReloadSearchAnalyzers) WithExpandWildcards(v string) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesReloadSearchAnalyzers) WithIgnoreUnavailable(v bool) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesReloadSearchAnalyzers) WithPretty() func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesReloadSearchAnalyzers) WithHuman() func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesReloadSearchAnalyzers) WithErrorTrace() func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesReloadSearchAnalyzers) WithFilterPath(v ...string) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesReloadSearchAnalyzers) WithHeader(h map[string]string) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesReloadSearchAnalyzers) WithOpaqueID(s string) func(*IndicesReloadSearchAnalyzersRequest) {
+	return func(r *IndicesReloadSearchAnalyzersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.indices.unfreeze.go b/esapi/api.xpack.indices.unfreeze.go
new file mode 100644
index 0000000000..e303f3671b
--- /dev/null
+++ b/esapi/api.xpack.indices.unfreeze.go
@@ -0,0 +1,282 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newIndicesUnfreezeFunc(t Transport) IndicesUnfreeze {
+	return func(index string, o ...func(*IndicesUnfreezeRequest)) (*Response, error) {
+		var r = IndicesUnfreezeRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// IndicesUnfreeze - Unfreezes an index. When a frozen index is unfrozen, the index goes through the normal recovery process and becomes writeable again.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/unfreeze-index-api.html.
+//
+type IndicesUnfreeze func(index string, o ...func(*IndicesUnfreezeRequest)) (*Response, error)
+
+// IndicesUnfreezeRequest configures the Indices Unfreeze API request.
+//
+type IndicesUnfreezeRequest struct {
+	Index string
+
+	AllowNoIndices      *bool
+	ExpandWildcards     string
+	IgnoreUnavailable   *bool
+	MasterTimeout       time.Duration
+	Timeout             time.Duration
+	WaitForActiveShards string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r IndicesUnfreezeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_unfreeze"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_unfreeze")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForActiveShards != "" {
+		params["wait_for_active_shards"] = r.WaitForActiveShards
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f IndicesUnfreeze) WithContext(v context.Context) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f IndicesUnfreeze) WithAllowNoIndices(v bool) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f IndicesUnfreeze) WithExpandWildcards(v string) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f IndicesUnfreeze) WithIgnoreUnavailable(v bool) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithMasterTimeout - specify timeout for connection to master.
+//
+func (f IndicesUnfreeze) WithMasterTimeout(v time.Duration) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithTimeout - explicit operation timeout.
+//
+func (f IndicesUnfreeze) WithTimeout(v time.Duration) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForActiveShards - sets the number of active shards to wait for before the operation returns..
+//
+func (f IndicesUnfreeze) WithWaitForActiveShards(v string) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.WaitForActiveShards = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f IndicesUnfreeze) WithPretty() func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f IndicesUnfreeze) WithHuman() func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f IndicesUnfreeze) WithErrorTrace() func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f IndicesUnfreeze) WithFilterPath(v ...string) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f IndicesUnfreeze) WithHeader(h map[string]string) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f IndicesUnfreeze) WithOpaqueID(s string) func(*IndicesUnfreezeRequest) {
+	return func(r *IndicesUnfreezeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.delete.go b/esapi/api.xpack.license.delete.go
new file mode 100644
index 0000000000..2511bd1c80
--- /dev/null
+++ b/esapi/api.xpack.license.delete.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newLicenseDeleteFunc(t Transport) LicenseDelete {
+	return func(o ...func(*LicenseDeleteRequest)) (*Response, error) {
+		var r = LicenseDeleteRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicenseDelete - Deletes licensing information for the cluster
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-license.html.
+//
+type LicenseDelete func(o ...func(*LicenseDeleteRequest)) (*Response, error)
+
+// LicenseDeleteRequest configures the License Delete API request.
+//
+type LicenseDeleteRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicenseDeleteRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(len("/_license"))
+	path.WriteString("/_license")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicenseDelete) WithContext(v context.Context) func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicenseDelete) WithPretty() func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicenseDelete) WithHuman() func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicenseDelete) WithErrorTrace() func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicenseDelete) WithFilterPath(v ...string) func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicenseDelete) WithHeader(h map[string]string) func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicenseDelete) WithOpaqueID(s string) func(*LicenseDeleteRequest) {
+	return func(r *LicenseDeleteRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.get.go b/esapi/api.xpack.license.get.go
new file mode 100644
index 0000000000..8f9b3c765c
--- /dev/null
+++ b/esapi/api.xpack.license.get.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newLicenseGetFunc(t Transport) LicenseGet {
+	return func(o ...func(*LicenseGetRequest)) (*Response, error) {
+		var r = LicenseGetRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicenseGet - Retrieves licensing information for the cluster
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-license.html.
+//
+type LicenseGet func(o ...func(*LicenseGetRequest)) (*Response, error)
+
+// LicenseGetRequest configures the License Get API request.
+//
+type LicenseGetRequest struct {
+	AcceptEnterprise *bool
+	Local            *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicenseGetRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_license"))
+	path.WriteString("/_license")
+
+	params = make(map[string]string)
+
+	if r.AcceptEnterprise != nil {
+		params["accept_enterprise"] = strconv.FormatBool(*r.AcceptEnterprise)
+	}
+
+	if r.Local != nil {
+		params["local"] = strconv.FormatBool(*r.Local)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicenseGet) WithContext(v context.Context) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcceptEnterprise - if the active license is an enterprise license, return type as 'enterprise' (default: false).
+//
+func (f LicenseGet) WithAcceptEnterprise(v bool) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.AcceptEnterprise = &v
+	}
+}
+
+// WithLocal - return local information, do not retrieve the state from master node (default: false).
+//
+func (f LicenseGet) WithLocal(v bool) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.Local = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicenseGet) WithPretty() func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicenseGet) WithHuman() func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicenseGet) WithErrorTrace() func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicenseGet) WithFilterPath(v ...string) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicenseGet) WithHeader(h map[string]string) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicenseGet) WithOpaqueID(s string) func(*LicenseGetRequest) {
+	return func(r *LicenseGetRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.get_basic_status.go b/esapi/api.xpack.license.get_basic_status.go
new file mode 100644
index 0000000000..7f1dd5c32c
--- /dev/null
+++ b/esapi/api.xpack.license.get_basic_status.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newLicenseGetBasicStatusFunc(t Transport) LicenseGetBasicStatus {
+	return func(o ...func(*LicenseGetBasicStatusRequest)) (*Response, error) {
+		var r = LicenseGetBasicStatusRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicenseGetBasicStatus - Retrieves information about the status of the basic license.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-basic-status.html.
+//
+type LicenseGetBasicStatus func(o ...func(*LicenseGetBasicStatusRequest)) (*Response, error)
+
+// LicenseGetBasicStatusRequest configures the License Get Basic Status API request.
+//
+type LicenseGetBasicStatusRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicenseGetBasicStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_license/basic_status"))
+	path.WriteString("/_license/basic_status")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicenseGetBasicStatus) WithContext(v context.Context) func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicenseGetBasicStatus) WithPretty() func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicenseGetBasicStatus) WithHuman() func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicenseGetBasicStatus) WithErrorTrace() func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicenseGetBasicStatus) WithFilterPath(v ...string) func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicenseGetBasicStatus) WithHeader(h map[string]string) func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicenseGetBasicStatus) WithOpaqueID(s string) func(*LicenseGetBasicStatusRequest) {
+	return func(r *LicenseGetBasicStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.get_trial_status.go b/esapi/api.xpack.license.get_trial_status.go
new file mode 100644
index 0000000000..da995ab983
--- /dev/null
+++ b/esapi/api.xpack.license.get_trial_status.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newLicenseGetTrialStatusFunc(t Transport) LicenseGetTrialStatus {
+	return func(o ...func(*LicenseGetTrialStatusRequest)) (*Response, error) {
+		var r = LicenseGetTrialStatusRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicenseGetTrialStatus - Retrieves information about the status of the trial license.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-trial-status.html.
+//
+type LicenseGetTrialStatus func(o ...func(*LicenseGetTrialStatusRequest)) (*Response, error)
+
+// LicenseGetTrialStatusRequest configures the License Get Trial Status API request.
+//
+type LicenseGetTrialStatusRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicenseGetTrialStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_license/trial_status"))
+	path.WriteString("/_license/trial_status")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicenseGetTrialStatus) WithContext(v context.Context) func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicenseGetTrialStatus) WithPretty() func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicenseGetTrialStatus) WithHuman() func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicenseGetTrialStatus) WithErrorTrace() func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicenseGetTrialStatus) WithFilterPath(v ...string) func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicenseGetTrialStatus) WithHeader(h map[string]string) func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicenseGetTrialStatus) WithOpaqueID(s string) func(*LicenseGetTrialStatusRequest) {
+	return func(r *LicenseGetTrialStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.post.go b/esapi/api.xpack.license.post.go
new file mode 100644
index 0000000000..5469209317
--- /dev/null
+++ b/esapi/api.xpack.license.post.go
@@ -0,0 +1,226 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newLicensePostFunc(t Transport) LicensePost {
+	return func(o ...func(*LicensePostRequest)) (*Response, error) {
+		var r = LicensePostRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicensePost - Updates the license for the cluster.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/update-license.html.
+//
+type LicensePost func(o ...func(*LicensePostRequest)) (*Response, error)
+
+// LicensePostRequest configures the License Post API request.
+//
+type LicensePostRequest struct {
+	Body io.Reader
+
+	Acknowledge *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicensePostRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(len("/_license"))
+	path.WriteString("/_license")
+
+	params = make(map[string]string)
+
+	if r.Acknowledge != nil {
+		params["acknowledge"] = strconv.FormatBool(*r.Acknowledge)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicensePost) WithContext(v context.Context) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - licenses to be installed.
+//
+func (f LicensePost) WithBody(v io.Reader) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.Body = v
+	}
+}
+
+// WithAcknowledge - whether the user has acknowledged acknowledge messages (default: false).
+//
+func (f LicensePost) WithAcknowledge(v bool) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.Acknowledge = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicensePost) WithPretty() func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicensePost) WithHuman() func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicensePost) WithErrorTrace() func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicensePost) WithFilterPath(v ...string) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicensePost) WithHeader(h map[string]string) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicensePost) WithOpaqueID(s string) func(*LicensePostRequest) {
+	return func(r *LicensePostRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.post_start_basic.go b/esapi/api.xpack.license.post_start_basic.go
new file mode 100644
index 0000000000..6c76712712
--- /dev/null
+++ b/esapi/api.xpack.license.post_start_basic.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newLicensePostStartBasicFunc(t Transport) LicensePostStartBasic {
+	return func(o ...func(*LicensePostStartBasicRequest)) (*Response, error) {
+		var r = LicensePostStartBasicRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicensePostStartBasic - Starts an indefinite basic license.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/start-basic.html.
+//
+type LicensePostStartBasic func(o ...func(*LicensePostStartBasicRequest)) (*Response, error)
+
+// LicensePostStartBasicRequest configures the License Post Start Basic API request.
+//
+type LicensePostStartBasicRequest struct {
+	Acknowledge *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicensePostStartBasicRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_license/start_basic"))
+	path.WriteString("/_license/start_basic")
+
+	params = make(map[string]string)
+
+	if r.Acknowledge != nil {
+		params["acknowledge"] = strconv.FormatBool(*r.Acknowledge)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicensePostStartBasic) WithContext(v context.Context) func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcknowledge - whether the user has acknowledged acknowledge messages (default: false).
+//
+func (f LicensePostStartBasic) WithAcknowledge(v bool) func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.Acknowledge = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicensePostStartBasic) WithPretty() func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicensePostStartBasic) WithHuman() func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicensePostStartBasic) WithErrorTrace() func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicensePostStartBasic) WithFilterPath(v ...string) func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicensePostStartBasic) WithHeader(h map[string]string) func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicensePostStartBasic) WithOpaqueID(s string) func(*LicensePostStartBasicRequest) {
+	return func(r *LicensePostStartBasicRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.license.post_start_trial.go b/esapi/api.xpack.license.post_start_trial.go
new file mode 100644
index 0000000000..2d91096bab
--- /dev/null
+++ b/esapi/api.xpack.license.post_start_trial.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newLicensePostStartTrialFunc(t Transport) LicensePostStartTrial {
+	return func(o ...func(*LicensePostStartTrialRequest)) (*Response, error) {
+		var r = LicensePostStartTrialRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LicensePostStartTrial - starts a limited time trial license.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/start-trial.html.
+//
+type LicensePostStartTrial func(o ...func(*LicensePostStartTrialRequest)) (*Response, error)
+
+// LicensePostStartTrialRequest configures the License Post Start Trial API request.
+//
+type LicensePostStartTrialRequest struct {
+	Acknowledge  *bool
+	DocumentType string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LicensePostStartTrialRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_license/start_trial"))
+	path.WriteString("/_license/start_trial")
+
+	params = make(map[string]string)
+
+	if r.Acknowledge != nil {
+		params["acknowledge"] = strconv.FormatBool(*r.Acknowledge)
+	}
+
+	if r.DocumentType != "" {
+		params["type"] = r.DocumentType
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LicensePostStartTrial) WithContext(v context.Context) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcknowledge - whether the user has acknowledged acknowledge messages (default: false).
+//
+func (f LicensePostStartTrial) WithAcknowledge(v bool) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.Acknowledge = &v
+	}
+}
+
+// WithDocumentType - the type of trial license to generate (default: "trial").
+//
+func (f LicensePostStartTrial) WithDocumentType(v string) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.DocumentType = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LicensePostStartTrial) WithPretty() func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LicensePostStartTrial) WithHuman() func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LicensePostStartTrial) WithErrorTrace() func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LicensePostStartTrial) WithFilterPath(v ...string) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LicensePostStartTrial) WithHeader(h map[string]string) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LicensePostStartTrial) WithOpaqueID(s string) func(*LicensePostStartTrialRequest) {
+	return func(r *LicensePostStartTrialRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.logstash.delete_pipeline.go b/esapi/api.xpack.logstash.delete_pipeline.go
new file mode 100644
index 0000000000..35bc6bcd74
--- /dev/null
+++ b/esapi/api.xpack.logstash.delete_pipeline.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newLogstashDeletePipelineFunc(t Transport) LogstashDeletePipeline {
+	return func(id string, o ...func(*LogstashDeletePipelineRequest)) (*Response, error) {
+		var r = LogstashDeletePipelineRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LogstashDeletePipeline - Deletes Logstash Pipelines used by Central Management
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/logstash-api-delete-pipeline.html.
+//
+type LogstashDeletePipeline func(id string, o ...func(*LogstashDeletePipelineRequest)) (*Response, error)
+
+// LogstashDeletePipelineRequest configures the Logstash Delete Pipeline API request.
+//
+type LogstashDeletePipelineRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LogstashDeletePipelineRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_logstash") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_logstash")
+	path.WriteString("/")
+	path.WriteString("pipeline")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LogstashDeletePipeline) WithContext(v context.Context) func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LogstashDeletePipeline) WithPretty() func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LogstashDeletePipeline) WithHuman() func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LogstashDeletePipeline) WithErrorTrace() func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LogstashDeletePipeline) WithFilterPath(v ...string) func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LogstashDeletePipeline) WithHeader(h map[string]string) func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LogstashDeletePipeline) WithOpaqueID(s string) func(*LogstashDeletePipelineRequest) {
+	return func(r *LogstashDeletePipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.logstash.get_pipeline.go b/esapi/api.xpack.logstash.get_pipeline.go
new file mode 100644
index 0000000000..9a22e35d4b
--- /dev/null
+++ b/esapi/api.xpack.logstash.get_pipeline.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newLogstashGetPipelineFunc(t Transport) LogstashGetPipeline {
+	return func(id string, o ...func(*LogstashGetPipelineRequest)) (*Response, error) {
+		var r = LogstashGetPipelineRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LogstashGetPipeline - Retrieves Logstash Pipelines used by Central Management
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/logstash-api-get-pipeline.html.
+//
+type LogstashGetPipeline func(id string, o ...func(*LogstashGetPipelineRequest)) (*Response, error)
+
+// LogstashGetPipelineRequest configures the Logstash Get Pipeline API request.
+//
+type LogstashGetPipelineRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LogstashGetPipelineRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_logstash") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_logstash")
+	path.WriteString("/")
+	path.WriteString("pipeline")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LogstashGetPipeline) WithContext(v context.Context) func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LogstashGetPipeline) WithPretty() func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LogstashGetPipeline) WithHuman() func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LogstashGetPipeline) WithErrorTrace() func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LogstashGetPipeline) WithFilterPath(v ...string) func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LogstashGetPipeline) WithHeader(h map[string]string) func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LogstashGetPipeline) WithOpaqueID(s string) func(*LogstashGetPipelineRequest) {
+	return func(r *LogstashGetPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.logstash.put_pipeline.go b/esapi/api.xpack.logstash.put_pipeline.go
new file mode 100644
index 0000000000..8e4c7ed72c
--- /dev/null
+++ b/esapi/api.xpack.logstash.put_pipeline.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newLogstashPutPipelineFunc(t Transport) LogstashPutPipeline {
+	return func(id string, body io.Reader, o ...func(*LogstashPutPipelineRequest)) (*Response, error) {
+		var r = LogstashPutPipelineRequest{DocumentID: id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// LogstashPutPipeline - Adds and updates Logstash Pipelines used for Central Management
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/logstash-api-put-pipeline.html.
+//
+type LogstashPutPipeline func(id string, body io.Reader, o ...func(*LogstashPutPipelineRequest)) (*Response, error)
+
+// LogstashPutPipelineRequest configures the Logstash Put Pipeline API request.
+//
+type LogstashPutPipelineRequest struct {
+	DocumentID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r LogstashPutPipelineRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_logstash") + 1 + len("pipeline") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_logstash")
+	path.WriteString("/")
+	path.WriteString("pipeline")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f LogstashPutPipeline) WithContext(v context.Context) func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f LogstashPutPipeline) WithPretty() func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f LogstashPutPipeline) WithHuman() func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f LogstashPutPipeline) WithErrorTrace() func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f LogstashPutPipeline) WithFilterPath(v ...string) func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f LogstashPutPipeline) WithHeader(h map[string]string) func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f LogstashPutPipeline) WithOpaqueID(s string) func(*LogstashPutPipelineRequest) {
+	return func(r *LogstashPutPipelineRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.migration.deprecations.go b/esapi/api.xpack.migration.deprecations.go
new file mode 100644
index 0000000000..569a8ff2cd
--- /dev/null
+++ b/esapi/api.xpack.migration.deprecations.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMigrationDeprecationsFunc(t Transport) MigrationDeprecations {
+	return func(o ...func(*MigrationDeprecationsRequest)) (*Response, error) {
+		var r = MigrationDeprecationsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MigrationDeprecations - Retrieves information about different cluster, node, and index level settings that use deprecated features that will be removed or changed in the next major version.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-deprecation.html.
+//
+type MigrationDeprecations func(o ...func(*MigrationDeprecationsRequest)) (*Response, error)
+
+// MigrationDeprecationsRequest configures the Migration Deprecations API request.
+//
+type MigrationDeprecationsRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MigrationDeprecationsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_migration") + 1 + len("deprecations"))
+	if r.Index != "" {
+		path.WriteString("/")
+		path.WriteString(r.Index)
+	}
+	path.WriteString("/")
+	path.WriteString("_migration")
+	path.WriteString("/")
+	path.WriteString("deprecations")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MigrationDeprecations) WithContext(v context.Context) func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithIndex - index pattern.
+//
+func (f MigrationDeprecations) WithIndex(v string) func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.Index = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MigrationDeprecations) WithPretty() func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MigrationDeprecations) WithHuman() func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MigrationDeprecations) WithErrorTrace() func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MigrationDeprecations) WithFilterPath(v ...string) func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MigrationDeprecations) WithHeader(h map[string]string) func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MigrationDeprecations) WithOpaqueID(s string) func(*MigrationDeprecationsRequest) {
+	return func(r *MigrationDeprecationsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.migration.get_feature_upgrade_status.go b/esapi/api.xpack.migration.get_feature_upgrade_status.go
new file mode 100644
index 0000000000..7c3d082bb2
--- /dev/null
+++ b/esapi/api.xpack.migration.get_feature_upgrade_status.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMigrationGetFeatureUpgradeStatusFunc(t Transport) MigrationGetFeatureUpgradeStatus {
+	return func(o ...func(*MigrationGetFeatureUpgradeStatusRequest)) (*Response, error) {
+		var r = MigrationGetFeatureUpgradeStatusRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MigrationGetFeatureUpgradeStatus - Find out whether system features need to be upgraded or not
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-feature-upgrade.html.
+//
+type MigrationGetFeatureUpgradeStatus func(o ...func(*MigrationGetFeatureUpgradeStatusRequest)) (*Response, error)
+
+// MigrationGetFeatureUpgradeStatusRequest configures the Migration Get Feature Upgrade Status API request.
+//
+type MigrationGetFeatureUpgradeStatusRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MigrationGetFeatureUpgradeStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_migration/system_features"))
+	path.WriteString("/_migration/system_features")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithContext(v context.Context) func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithPretty() func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithHuman() func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithErrorTrace() func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithFilterPath(v ...string) func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithHeader(h map[string]string) func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MigrationGetFeatureUpgradeStatus) WithOpaqueID(s string) func(*MigrationGetFeatureUpgradeStatusRequest) {
+	return func(r *MigrationGetFeatureUpgradeStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.migration.post_feature_upgrade.go b/esapi/api.xpack.migration.post_feature_upgrade.go
new file mode 100644
index 0000000000..a112dffb7c
--- /dev/null
+++ b/esapi/api.xpack.migration.post_feature_upgrade.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMigrationPostFeatureUpgradeFunc(t Transport) MigrationPostFeatureUpgrade {
+	return func(o ...func(*MigrationPostFeatureUpgradeRequest)) (*Response, error) {
+		var r = MigrationPostFeatureUpgradeRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MigrationPostFeatureUpgrade - Begin upgrades for system features
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-feature-upgrade.html.
+//
+type MigrationPostFeatureUpgrade func(o ...func(*MigrationPostFeatureUpgradeRequest)) (*Response, error)
+
+// MigrationPostFeatureUpgradeRequest configures the Migration Post Feature Upgrade API request.
+//
+type MigrationPostFeatureUpgradeRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MigrationPostFeatureUpgradeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_migration/system_features"))
+	path.WriteString("/_migration/system_features")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MigrationPostFeatureUpgrade) WithContext(v context.Context) func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MigrationPostFeatureUpgrade) WithPretty() func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MigrationPostFeatureUpgrade) WithHuman() func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MigrationPostFeatureUpgrade) WithErrorTrace() func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MigrationPostFeatureUpgrade) WithFilterPath(v ...string) func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MigrationPostFeatureUpgrade) WithHeader(h map[string]string) func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MigrationPostFeatureUpgrade) WithOpaqueID(s string) func(*MigrationPostFeatureUpgradeRequest) {
+	return func(r *MigrationPostFeatureUpgradeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.close_job.go b/esapi/api.xpack.ml.close_job.go
new file mode 100644
index 0000000000..9cce4fd01f
--- /dev/null
+++ b/esapi/api.xpack.ml.close_job.go
@@ -0,0 +1,275 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLCloseJobFunc(t Transport) MLCloseJob {
+	return func(job_id string, o ...func(*MLCloseJobRequest)) (*Response, error) {
+		var r = MLCloseJobRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLCloseJob - Closes one or more anomaly detection jobs. A job can be opened and closed multiple times throughout its lifecycle.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-close-job.html.
+//
+type MLCloseJob func(job_id string, o ...func(*MLCloseJobRequest)) (*Response, error)
+
+// MLCloseJobRequest configures the ML Close Job API request.
+//
+type MLCloseJobRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	AllowNoJobs  *bool
+	AllowNoMatch *bool
+	Force        *bool
+	Timeout      time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLCloseJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_close"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_close")
+
+	params = make(map[string]string)
+
+	if r.AllowNoJobs != nil {
+		params["allow_no_jobs"] = strconv.FormatBool(*r.AllowNoJobs)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLCloseJob) WithContext(v context.Context) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The URL params optionally sent in the body.
+//
+func (f MLCloseJob) WithBody(v io.Reader) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.Body = v
+	}
+}
+
+// WithAllowNoJobs - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLCloseJob) WithAllowNoJobs(v bool) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.AllowNoJobs = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLCloseJob) WithAllowNoMatch(v bool) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithForce - true if the job should be forcefully closed.
+//
+func (f MLCloseJob) WithForce(v bool) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until a job has closed. default to 30 minutes.
+//
+func (f MLCloseJob) WithTimeout(v time.Duration) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLCloseJob) WithPretty() func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLCloseJob) WithHuman() func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLCloseJob) WithErrorTrace() func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLCloseJob) WithFilterPath(v ...string) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLCloseJob) WithHeader(h map[string]string) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLCloseJob) WithOpaqueID(s string) func(*MLCloseJobRequest) {
+	return func(r *MLCloseJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_calendar.go b/esapi/api.xpack.ml.delete_calendar.go
new file mode 100644
index 0000000000..36674aec88
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_calendar.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteCalendarFunc(t Transport) MLDeleteCalendar {
+	return func(calendar_id string, o ...func(*MLDeleteCalendarRequest)) (*Response, error) {
+		var r = MLDeleteCalendarRequest{CalendarID: calendar_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteCalendar - Deletes a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-calendar.html.
+//
+type MLDeleteCalendar func(calendar_id string, o ...func(*MLDeleteCalendarRequest)) (*Response, error)
+
+// MLDeleteCalendarRequest configures the ML Delete Calendar API request.
+//
+type MLDeleteCalendarRequest struct {
+	CalendarID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteCalendarRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteCalendar) WithContext(v context.Context) func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteCalendar) WithPretty() func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteCalendar) WithHuman() func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteCalendar) WithErrorTrace() func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteCalendar) WithFilterPath(v ...string) func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteCalendar) WithHeader(h map[string]string) func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteCalendar) WithOpaqueID(s string) func(*MLDeleteCalendarRequest) {
+	return func(r *MLDeleteCalendarRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_calendar_event.go b/esapi/api.xpack.ml.delete_calendar_event.go
new file mode 100644
index 0000000000..c520ec180b
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_calendar_event.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteCalendarEventFunc(t Transport) MLDeleteCalendarEvent {
+	return func(calendar_id string, event_id string, o ...func(*MLDeleteCalendarEventRequest)) (*Response, error) {
+		var r = MLDeleteCalendarEventRequest{CalendarID: calendar_id, EventID: event_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteCalendarEvent - Deletes scheduled events from a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-calendar-event.html.
+//
+type MLDeleteCalendarEvent func(calendar_id string, event_id string, o ...func(*MLDeleteCalendarEventRequest)) (*Response, error)
+
+// MLDeleteCalendarEventRequest configures the ML Delete Calendar Event API request.
+//
+type MLDeleteCalendarEventRequest struct {
+	CalendarID string
+	EventID    string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteCalendarEventRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID) + 1 + len("events") + 1 + len(r.EventID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+	path.WriteString("/")
+	path.WriteString("events")
+	path.WriteString("/")
+	path.WriteString(r.EventID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteCalendarEvent) WithContext(v context.Context) func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteCalendarEvent) WithPretty() func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteCalendarEvent) WithHuman() func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteCalendarEvent) WithErrorTrace() func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteCalendarEvent) WithFilterPath(v ...string) func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteCalendarEvent) WithHeader(h map[string]string) func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteCalendarEvent) WithOpaqueID(s string) func(*MLDeleteCalendarEventRequest) {
+	return func(r *MLDeleteCalendarEventRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_calendar_job.go b/esapi/api.xpack.ml.delete_calendar_job.go
new file mode 100644
index 0000000000..364ce605bd
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_calendar_job.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteCalendarJobFunc(t Transport) MLDeleteCalendarJob {
+	return func(calendar_id string, job_id string, o ...func(*MLDeleteCalendarJobRequest)) (*Response, error) {
+		var r = MLDeleteCalendarJobRequest{CalendarID: calendar_id, JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteCalendarJob - Deletes anomaly detection jobs from a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-calendar-job.html.
+//
+type MLDeleteCalendarJob func(calendar_id string, job_id string, o ...func(*MLDeleteCalendarJobRequest)) (*Response, error)
+
+// MLDeleteCalendarJobRequest configures the ML Delete Calendar Job API request.
+//
+type MLDeleteCalendarJobRequest struct {
+	CalendarID string
+	JobID      string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteCalendarJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID) + 1 + len("jobs") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+	path.WriteString("/")
+	path.WriteString("jobs")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteCalendarJob) WithContext(v context.Context) func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteCalendarJob) WithPretty() func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteCalendarJob) WithHuman() func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteCalendarJob) WithErrorTrace() func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteCalendarJob) WithFilterPath(v ...string) func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteCalendarJob) WithHeader(h map[string]string) func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteCalendarJob) WithOpaqueID(s string) func(*MLDeleteCalendarJobRequest) {
+	return func(r *MLDeleteCalendarJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_data_frame_analytics.go b/esapi/api.xpack.ml.delete_data_frame_analytics.go
new file mode 100644
index 0000000000..b0d96b120a
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_data_frame_analytics.go
@@ -0,0 +1,234 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLDeleteDataFrameAnalyticsFunc(t Transport) MLDeleteDataFrameAnalytics {
+	return func(id string, o ...func(*MLDeleteDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLDeleteDataFrameAnalyticsRequest{ID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteDataFrameAnalytics - Deletes an existing data frame analytics job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-dfanalytics.html.
+//
+type MLDeleteDataFrameAnalytics func(id string, o ...func(*MLDeleteDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLDeleteDataFrameAnalyticsRequest configures the ML Delete Data Frame Analytics API request.
+//
+type MLDeleteDataFrameAnalyticsRequest struct {
+	ID string
+
+	Force   *bool
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	path.WriteString("/")
+	path.WriteString(r.ID)
+
+	params = make(map[string]string)
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteDataFrameAnalytics) WithContext(v context.Context) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForce - true if the job should be forcefully deleted.
+//
+func (f MLDeleteDataFrameAnalytics) WithForce(v bool) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until a job is deleted. defaults to 1 minute.
+//
+func (f MLDeleteDataFrameAnalytics) WithTimeout(v time.Duration) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteDataFrameAnalytics) WithPretty() func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteDataFrameAnalytics) WithHuman() func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteDataFrameAnalytics) WithErrorTrace() func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteDataFrameAnalytics) WithFilterPath(v ...string) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteDataFrameAnalytics) WithHeader(h map[string]string) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteDataFrameAnalytics) WithOpaqueID(s string) func(*MLDeleteDataFrameAnalyticsRequest) {
+	return func(r *MLDeleteDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_datafeed.go b/esapi/api.xpack.ml.delete_datafeed.go
new file mode 100644
index 0000000000..1efb7c98e9
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_datafeed.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLDeleteDatafeedFunc(t Transport) MLDeleteDatafeed {
+	return func(datafeed_id string, o ...func(*MLDeleteDatafeedRequest)) (*Response, error) {
+		var r = MLDeleteDatafeedRequest{DatafeedID: datafeed_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteDatafeed - Deletes an existing datafeed.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-datafeed.html.
+//
+type MLDeleteDatafeed func(datafeed_id string, o ...func(*MLDeleteDatafeedRequest)) (*Response, error)
+
+// MLDeleteDatafeedRequest configures the ML Delete Datafeed API request.
+//
+type MLDeleteDatafeedRequest struct {
+	DatafeedID string
+
+	Force *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	path.WriteString("/")
+	path.WriteString(r.DatafeedID)
+
+	params = make(map[string]string)
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteDatafeed) WithContext(v context.Context) func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForce - true if the datafeed should be forcefully deleted.
+//
+func (f MLDeleteDatafeed) WithForce(v bool) func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.Force = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteDatafeed) WithPretty() func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteDatafeed) WithHuman() func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteDatafeed) WithErrorTrace() func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteDatafeed) WithFilterPath(v ...string) func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteDatafeed) WithHeader(h map[string]string) func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteDatafeed) WithOpaqueID(s string) func(*MLDeleteDatafeedRequest) {
+	return func(r *MLDeleteDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_expired_data.go b/esapi/api.xpack.ml.delete_expired_data.go
new file mode 100644
index 0000000000..fa54be4f32
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_expired_data.go
@@ -0,0 +1,257 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLDeleteExpiredDataFunc(t Transport) MLDeleteExpiredData {
+	return func(o ...func(*MLDeleteExpiredDataRequest)) (*Response, error) {
+		var r = MLDeleteExpiredDataRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteExpiredData - Deletes expired and unused machine learning data.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-expired-data.html.
+//
+type MLDeleteExpiredData func(o ...func(*MLDeleteExpiredDataRequest)) (*Response, error)
+
+// MLDeleteExpiredDataRequest configures the ML Delete Expired Data API request.
+//
+type MLDeleteExpiredDataRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	RequestsPerSecond *int
+	Timeout           time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteExpiredDataRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("_delete_expired_data") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("_delete_expired_data")
+	if r.JobID != "" {
+		path.WriteString("/")
+		path.WriteString(r.JobID)
+	}
+
+	params = make(map[string]string)
+
+	if r.RequestsPerSecond != nil {
+		params["requests_per_second"] = strconv.FormatInt(int64(*r.RequestsPerSecond), 10)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteExpiredData) WithContext(v context.Context) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - deleting expired data parameters.
+//
+func (f MLDeleteExpiredData) WithBody(v io.Reader) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.Body = v
+	}
+}
+
+// WithJobID - the ID of the job(s) to perform expired data hygiene for.
+//
+func (f MLDeleteExpiredData) WithJobID(v string) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.JobID = v
+	}
+}
+
+// WithRequestsPerSecond - the desired requests per second for the deletion processes..
+//
+func (f MLDeleteExpiredData) WithRequestsPerSecond(v int) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.RequestsPerSecond = &v
+	}
+}
+
+// WithTimeout - how long can the underlying delete processes run until they are canceled.
+//
+func (f MLDeleteExpiredData) WithTimeout(v time.Duration) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteExpiredData) WithPretty() func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteExpiredData) WithHuman() func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteExpiredData) WithErrorTrace() func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteExpiredData) WithFilterPath(v ...string) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteExpiredData) WithHeader(h map[string]string) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteExpiredData) WithOpaqueID(s string) func(*MLDeleteExpiredDataRequest) {
+	return func(r *MLDeleteExpiredDataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_filter.go b/esapi/api.xpack.ml.delete_filter.go
new file mode 100644
index 0000000000..6b75a46074
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_filter.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteFilterFunc(t Transport) MLDeleteFilter {
+	return func(filter_id string, o ...func(*MLDeleteFilterRequest)) (*Response, error) {
+		var r = MLDeleteFilterRequest{FilterID: filter_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteFilter - Deletes a filter.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-filter.html.
+//
+type MLDeleteFilter func(filter_id string, o ...func(*MLDeleteFilterRequest)) (*Response, error)
+
+// MLDeleteFilterRequest configures the ML Delete Filter API request.
+//
+type MLDeleteFilterRequest struct {
+	FilterID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteFilterRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("filters") + 1 + len(r.FilterID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("filters")
+	path.WriteString("/")
+	path.WriteString(r.FilterID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteFilter) WithContext(v context.Context) func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteFilter) WithPretty() func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteFilter) WithHuman() func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteFilter) WithErrorTrace() func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteFilter) WithFilterPath(v ...string) func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteFilter) WithHeader(h map[string]string) func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteFilter) WithOpaqueID(s string) func(*MLDeleteFilterRequest) {
+	return func(r *MLDeleteFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_forecast.go b/esapi/api.xpack.ml.delete_forecast.go
new file mode 100644
index 0000000000..7b061dfd49
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_forecast.go
@@ -0,0 +1,247 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLDeleteForecastFunc(t Transport) MLDeleteForecast {
+	return func(job_id string, o ...func(*MLDeleteForecastRequest)) (*Response, error) {
+		var r = MLDeleteForecastRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteForecast - Deletes forecasts from a machine learning job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html.
+//
+type MLDeleteForecast func(job_id string, o ...func(*MLDeleteForecastRequest)) (*Response, error)
+
+// MLDeleteForecastRequest configures the ML Delete Forecast API request.
+//
+type MLDeleteForecastRequest struct {
+	ForecastID string
+	JobID      string
+
+	AllowNoForecasts *bool
+	Timeout          time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteForecastRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_forecast") + 1 + len(r.ForecastID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_forecast")
+	if r.ForecastID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ForecastID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoForecasts != nil {
+		params["allow_no_forecasts"] = strconv.FormatBool(*r.AllowNoForecasts)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteForecast) WithContext(v context.Context) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForecastID - the ID of the forecast to delete, can be comma delimited list. leaving blank implies `_all`.
+//
+func (f MLDeleteForecast) WithForecastID(v string) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.ForecastID = v
+	}
+}
+
+// WithAllowNoForecasts - whether to ignore if `_all` matches no forecasts.
+//
+func (f MLDeleteForecast) WithAllowNoForecasts(v bool) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.AllowNoForecasts = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until the forecast(s) are deleted. default to 30 seconds.
+//
+func (f MLDeleteForecast) WithTimeout(v time.Duration) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteForecast) WithPretty() func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteForecast) WithHuman() func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteForecast) WithErrorTrace() func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteForecast) WithFilterPath(v ...string) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteForecast) WithHeader(h map[string]string) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteForecast) WithOpaqueID(s string) func(*MLDeleteForecastRequest) {
+	return func(r *MLDeleteForecastRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_job.go b/esapi/api.xpack.ml.delete_job.go
new file mode 100644
index 0000000000..fb3040cc38
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_job.go
@@ -0,0 +1,231 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLDeleteJobFunc(t Transport) MLDeleteJob {
+	return func(job_id string, o ...func(*MLDeleteJobRequest)) (*Response, error) {
+		var r = MLDeleteJobRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteJob - Deletes an existing anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html.
+//
+type MLDeleteJob func(job_id string, o ...func(*MLDeleteJobRequest)) (*Response, error)
+
+// MLDeleteJobRequest configures the ML Delete Job API request.
+//
+type MLDeleteJobRequest struct {
+	JobID string
+
+	Force             *bool
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteJob) WithContext(v context.Context) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForce - true if the job should be forcefully deleted.
+//
+func (f MLDeleteJob) WithForce(v bool) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.Force = &v
+	}
+}
+
+// WithWaitForCompletion - should this request wait until the operation has completed before returning.
+//
+func (f MLDeleteJob) WithWaitForCompletion(v bool) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteJob) WithPretty() func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteJob) WithHuman() func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteJob) WithErrorTrace() func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteJob) WithFilterPath(v ...string) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteJob) WithHeader(h map[string]string) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteJob) WithOpaqueID(s string) func(*MLDeleteJobRequest) {
+	return func(r *MLDeleteJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_model_snapshot.go b/esapi/api.xpack.ml.delete_model_snapshot.go
new file mode 100644
index 0000000000..69e1600c72
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_model_snapshot.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteModelSnapshotFunc(t Transport) MLDeleteModelSnapshot {
+	return func(snapshot_id string, job_id string, o ...func(*MLDeleteModelSnapshotRequest)) (*Response, error) {
+		var r = MLDeleteModelSnapshotRequest{SnapshotID: snapshot_id, JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteModelSnapshot - Deletes an existing model snapshot.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-snapshot.html.
+//
+type MLDeleteModelSnapshot func(snapshot_id string, job_id string, o ...func(*MLDeleteModelSnapshotRequest)) (*Response, error)
+
+// MLDeleteModelSnapshotRequest configures the ML Delete Model Snapshot API request.
+//
+type MLDeleteModelSnapshotRequest struct {
+	JobID      string
+	SnapshotID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteModelSnapshotRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("model_snapshots") + 1 + len(r.SnapshotID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("model_snapshots")
+	path.WriteString("/")
+	path.WriteString(r.SnapshotID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteModelSnapshot) WithContext(v context.Context) func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteModelSnapshot) WithPretty() func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteModelSnapshot) WithHuman() func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteModelSnapshot) WithErrorTrace() func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteModelSnapshot) WithFilterPath(v ...string) func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteModelSnapshot) WithHeader(h map[string]string) func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteModelSnapshot) WithOpaqueID(s string) func(*MLDeleteModelSnapshotRequest) {
+	return func(r *MLDeleteModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_trained_model.go b/esapi/api.xpack.ml.delete_trained_model.go
new file mode 100644
index 0000000000..1b685f1129
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_trained_model.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteTrainedModelFunc(t Transport) MLDeleteTrainedModel {
+	return func(model_id string, o ...func(*MLDeleteTrainedModelRequest)) (*Response, error) {
+		var r = MLDeleteTrainedModelRequest{ModelID: model_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteTrainedModel - Deletes an existing trained inference model that is currently not referenced by an ingest pipeline.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-trained-models.html.
+//
+type MLDeleteTrainedModel func(model_id string, o ...func(*MLDeleteTrainedModelRequest)) (*Response, error)
+
+// MLDeleteTrainedModelRequest configures the ML Delete Trained Model API request.
+//
+type MLDeleteTrainedModelRequest struct {
+	ModelID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteTrainedModelRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	path.WriteString("/")
+	path.WriteString(r.ModelID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteTrainedModel) WithContext(v context.Context) func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteTrainedModel) WithPretty() func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteTrainedModel) WithHuman() func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteTrainedModel) WithErrorTrace() func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteTrainedModel) WithFilterPath(v ...string) func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteTrainedModel) WithHeader(h map[string]string) func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteTrainedModel) WithOpaqueID(s string) func(*MLDeleteTrainedModelRequest) {
+	return func(r *MLDeleteTrainedModelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.delete_trained_model_alias.go b/esapi/api.xpack.ml.delete_trained_model_alias.go
new file mode 100644
index 0000000000..7f0ac8f138
--- /dev/null
+++ b/esapi/api.xpack.ml.delete_trained_model_alias.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLDeleteTrainedModelAliasFunc(t Transport) MLDeleteTrainedModelAlias {
+	return func(model_alias string, model_id string, o ...func(*MLDeleteTrainedModelAliasRequest)) (*Response, error) {
+		var r = MLDeleteTrainedModelAliasRequest{ModelAlias: model_alias, ModelID: model_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLDeleteTrainedModelAlias - Deletes a model alias that refers to the trained model
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-trained-models-aliases.html.
+//
+type MLDeleteTrainedModelAlias func(model_alias string, model_id string, o ...func(*MLDeleteTrainedModelAliasRequest)) (*Response, error)
+
+// MLDeleteTrainedModelAliasRequest configures the ML Delete Trained Model Alias API request.
+//
+type MLDeleteTrainedModelAliasRequest struct {
+	ModelAlias string
+	ModelID    string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLDeleteTrainedModelAliasRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID) + 1 + len("model_aliases") + 1 + len(r.ModelAlias))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	path.WriteString("/")
+	path.WriteString(r.ModelID)
+	path.WriteString("/")
+	path.WriteString("model_aliases")
+	path.WriteString("/")
+	path.WriteString(r.ModelAlias)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLDeleteTrainedModelAlias) WithContext(v context.Context) func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLDeleteTrainedModelAlias) WithPretty() func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLDeleteTrainedModelAlias) WithHuman() func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLDeleteTrainedModelAlias) WithErrorTrace() func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLDeleteTrainedModelAlias) WithFilterPath(v ...string) func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLDeleteTrainedModelAlias) WithHeader(h map[string]string) func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLDeleteTrainedModelAlias) WithOpaqueID(s string) func(*MLDeleteTrainedModelAliasRequest) {
+	return func(r *MLDeleteTrainedModelAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.estimate_model_memory.go b/esapi/api.xpack.ml.estimate_model_memory.go
new file mode 100644
index 0000000000..011e755532
--- /dev/null
+++ b/esapi/api.xpack.ml.estimate_model_memory.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLEstimateModelMemoryFunc(t Transport) MLEstimateModelMemory {
+	return func(body io.Reader, o ...func(*MLEstimateModelMemoryRequest)) (*Response, error) {
+		var r = MLEstimateModelMemoryRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLEstimateModelMemory - Estimates the model memory
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-apis.html.
+//
+type MLEstimateModelMemory func(body io.Reader, o ...func(*MLEstimateModelMemoryRequest)) (*Response, error)
+
+// MLEstimateModelMemoryRequest configures the ML Estimate Model Memory API request.
+//
+type MLEstimateModelMemoryRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLEstimateModelMemoryRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/anomaly_detectors/_estimate_model_memory"))
+	path.WriteString("/_ml/anomaly_detectors/_estimate_model_memory")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLEstimateModelMemory) WithContext(v context.Context) func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLEstimateModelMemory) WithPretty() func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLEstimateModelMemory) WithHuman() func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLEstimateModelMemory) WithErrorTrace() func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLEstimateModelMemory) WithFilterPath(v ...string) func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLEstimateModelMemory) WithHeader(h map[string]string) func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLEstimateModelMemory) WithOpaqueID(s string) func(*MLEstimateModelMemoryRequest) {
+	return func(r *MLEstimateModelMemoryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.evaluate_data_frame.go b/esapi/api.xpack.ml.evaluate_data_frame.go
new file mode 100644
index 0000000000..cd39bc6cb0
--- /dev/null
+++ b/esapi/api.xpack.ml.evaluate_data_frame.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLEvaluateDataFrameFunc(t Transport) MLEvaluateDataFrame {
+	return func(body io.Reader, o ...func(*MLEvaluateDataFrameRequest)) (*Response, error) {
+		var r = MLEvaluateDataFrameRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLEvaluateDataFrame - Evaluates the data frame analytics for an annotated index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/evaluate-dfanalytics.html.
+//
+type MLEvaluateDataFrame func(body io.Reader, o ...func(*MLEvaluateDataFrameRequest)) (*Response, error)
+
+// MLEvaluateDataFrameRequest configures the ML Evaluate Data Frame API request.
+//
+type MLEvaluateDataFrameRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLEvaluateDataFrameRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/data_frame/_evaluate"))
+	path.WriteString("/_ml/data_frame/_evaluate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLEvaluateDataFrame) WithContext(v context.Context) func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLEvaluateDataFrame) WithPretty() func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLEvaluateDataFrame) WithHuman() func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLEvaluateDataFrame) WithErrorTrace() func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLEvaluateDataFrame) WithFilterPath(v ...string) func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLEvaluateDataFrame) WithHeader(h map[string]string) func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLEvaluateDataFrame) WithOpaqueID(s string) func(*MLEvaluateDataFrameRequest) {
+	return func(r *MLEvaluateDataFrameRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.explain_data_frame_analytics.go b/esapi/api.xpack.ml.explain_data_frame_analytics.go
new file mode 100644
index 0000000000..3c6360ab73
--- /dev/null
+++ b/esapi/api.xpack.ml.explain_data_frame_analytics.go
@@ -0,0 +1,232 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLExplainDataFrameAnalyticsFunc(t Transport) MLExplainDataFrameAnalytics {
+	return func(o ...func(*MLExplainDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLExplainDataFrameAnalyticsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLExplainDataFrameAnalytics - Explains a data frame analytics config.
+//
+// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/explain-dfanalytics.html.
+//
+type MLExplainDataFrameAnalytics func(o ...func(*MLExplainDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLExplainDataFrameAnalyticsRequest configures the ML Explain Data Frame Analytics API request.
+//
+type MLExplainDataFrameAnalyticsRequest struct {
+	DocumentID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLExplainDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.DocumentID) + 1 + len("_explain"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	if r.DocumentID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentID)
+	}
+	path.WriteString("/")
+	path.WriteString("_explain")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLExplainDataFrameAnalytics) WithContext(v context.Context) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The data frame analytics config to explain.
+//
+func (f MLExplainDataFrameAnalytics) WithBody(v io.Reader) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.Body = v
+	}
+}
+
+// WithDocumentID - the ID of the data frame analytics to explain.
+//
+func (f MLExplainDataFrameAnalytics) WithDocumentID(v string) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.DocumentID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLExplainDataFrameAnalytics) WithPretty() func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLExplainDataFrameAnalytics) WithHuman() func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLExplainDataFrameAnalytics) WithErrorTrace() func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLExplainDataFrameAnalytics) WithFilterPath(v ...string) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLExplainDataFrameAnalytics) WithHeader(h map[string]string) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLExplainDataFrameAnalytics) WithOpaqueID(s string) func(*MLExplainDataFrameAnalyticsRequest) {
+	return func(r *MLExplainDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.find_file_structure.go b/esapi/api.xpack.ml.find_file_structure.go
new file mode 100644
index 0000000000..85a8cd591a
--- /dev/null
+++ b/esapi/api.xpack.ml.find_file_structure.go
@@ -0,0 +1,390 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLFindFileStructureFunc(t Transport) MLFindFileStructure {
+	return func(body io.Reader, o ...func(*MLFindFileStructureRequest)) (*Response, error) {
+		var r = MLFindFileStructureRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLFindFileStructure - Finds the structure of a text file. The text file must contain data that is suitable to be ingested into Elasticsearch.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/find-structure.html.
+//
+type MLFindFileStructure func(body io.Reader, o ...func(*MLFindFileStructureRequest)) (*Response, error)
+
+// MLFindFileStructureRequest configures the ML Find File Structure API request.
+//
+type MLFindFileStructureRequest struct {
+	Body io.Reader
+
+	Charset            string
+	ColumnNames        []string
+	Delimiter          string
+	Explain            *bool
+	Format             string
+	GrokPattern        string
+	HasHeaderRow       *bool
+	LineMergeSizeLimit *int
+	LinesToSample      *int
+	Quote              string
+	ShouldTrimFields   *bool
+	Timeout            time.Duration
+	TimestampField     string
+	TimestampFormat    string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLFindFileStructureRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/find_file_structure"))
+	path.WriteString("/_ml/find_file_structure")
+
+	params = make(map[string]string)
+
+	if r.Charset != "" {
+		params["charset"] = r.Charset
+	}
+
+	if len(r.ColumnNames) > 0 {
+		params["column_names"] = strings.Join(r.ColumnNames, ",")
+	}
+
+	if r.Delimiter != "" {
+		params["delimiter"] = r.Delimiter
+	}
+
+	if r.Explain != nil {
+		params["explain"] = strconv.FormatBool(*r.Explain)
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.GrokPattern != "" {
+		params["grok_pattern"] = r.GrokPattern
+	}
+
+	if r.HasHeaderRow != nil {
+		params["has_header_row"] = strconv.FormatBool(*r.HasHeaderRow)
+	}
+
+	if r.LineMergeSizeLimit != nil {
+		params["line_merge_size_limit"] = strconv.FormatInt(int64(*r.LineMergeSizeLimit), 10)
+	}
+
+	if r.LinesToSample != nil {
+		params["lines_to_sample"] = strconv.FormatInt(int64(*r.LinesToSample), 10)
+	}
+
+	if r.Quote != "" {
+		params["quote"] = r.Quote
+	}
+
+	if r.ShouldTrimFields != nil {
+		params["should_trim_fields"] = strconv.FormatBool(*r.ShouldTrimFields)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.TimestampField != "" {
+		params["timestamp_field"] = r.TimestampField
+	}
+
+	if r.TimestampFormat != "" {
+		params["timestamp_format"] = r.TimestampFormat
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLFindFileStructure) WithContext(v context.Context) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.ctx = v
+	}
+}
+
+// WithCharset - optional parameter to specify the character set of the file.
+//
+func (f MLFindFileStructure) WithCharset(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Charset = v
+	}
+}
+
+// WithColumnNames - optional parameter containing a comma separated list of the column names for a delimited file.
+//
+func (f MLFindFileStructure) WithColumnNames(v ...string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.ColumnNames = v
+	}
+}
+
+// WithDelimiter - optional parameter to specify the delimiter character for a delimited file - must be a single character.
+//
+func (f MLFindFileStructure) WithDelimiter(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Delimiter = v
+	}
+}
+
+// WithExplain - whether to include a commentary on how the structure was derived.
+//
+func (f MLFindFileStructure) WithExplain(v bool) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Explain = &v
+	}
+}
+
+// WithFormat - optional parameter to specify the high level file format.
+//
+func (f MLFindFileStructure) WithFormat(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Format = v
+	}
+}
+
+// WithGrokPattern - optional parameter to specify the grok pattern that should be used to extract fields from messages in a semi-structured text file.
+//
+func (f MLFindFileStructure) WithGrokPattern(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.GrokPattern = v
+	}
+}
+
+// WithHasHeaderRow - optional parameter to specify whether a delimited file includes the column names in its first row.
+//
+func (f MLFindFileStructure) WithHasHeaderRow(v bool) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.HasHeaderRow = &v
+	}
+}
+
+// WithLineMergeSizeLimit - maximum number of characters permitted in a single message when lines are merged to create messages..
+//
+func (f MLFindFileStructure) WithLineMergeSizeLimit(v int) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.LineMergeSizeLimit = &v
+	}
+}
+
+// WithLinesToSample - how many lines of the file should be included in the analysis.
+//
+func (f MLFindFileStructure) WithLinesToSample(v int) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.LinesToSample = &v
+	}
+}
+
+// WithQuote - optional parameter to specify the quote character for a delimited file - must be a single character.
+//
+func (f MLFindFileStructure) WithQuote(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Quote = v
+	}
+}
+
+// WithShouldTrimFields - optional parameter to specify whether the values between delimiters in a delimited file should have whitespace trimmed from them.
+//
+func (f MLFindFileStructure) WithShouldTrimFields(v bool) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.ShouldTrimFields = &v
+	}
+}
+
+// WithTimeout - timeout after which the analysis will be aborted.
+//
+func (f MLFindFileStructure) WithTimeout(v time.Duration) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithTimestampField - optional parameter to specify the timestamp field in the file.
+//
+func (f MLFindFileStructure) WithTimestampField(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.TimestampField = v
+	}
+}
+
+// WithTimestampFormat - optional parameter to specify the timestamp format in the file - may be either a joda or java time format.
+//
+func (f MLFindFileStructure) WithTimestampFormat(v string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.TimestampFormat = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLFindFileStructure) WithPretty() func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLFindFileStructure) WithHuman() func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLFindFileStructure) WithErrorTrace() func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLFindFileStructure) WithFilterPath(v ...string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLFindFileStructure) WithHeader(h map[string]string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLFindFileStructure) WithOpaqueID(s string) func(*MLFindFileStructureRequest) {
+	return func(r *MLFindFileStructureRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.flush_job.go b/esapi/api.xpack.ml.flush_job.go
new file mode 100644
index 0000000000..8e4b74114a
--- /dev/null
+++ b/esapi/api.xpack.ml.flush_job.go
@@ -0,0 +1,287 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLFlushJobFunc(t Transport) MLFlushJob {
+	return func(job_id string, o ...func(*MLFlushJobRequest)) (*Response, error) {
+		var r = MLFlushJobRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLFlushJob - Forces any buffered data to be processed by the job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-flush-job.html.
+//
+type MLFlushJob func(job_id string, o ...func(*MLFlushJobRequest)) (*Response, error)
+
+// MLFlushJobRequest configures the ML Flush Job API request.
+//
+type MLFlushJobRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	AdvanceTime string
+	CalcInterim *bool
+	End         string
+	SkipTime    string
+	Start       string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLFlushJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_flush"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_flush")
+
+	params = make(map[string]string)
+
+	if r.AdvanceTime != "" {
+		params["advance_time"] = r.AdvanceTime
+	}
+
+	if r.CalcInterim != nil {
+		params["calc_interim"] = strconv.FormatBool(*r.CalcInterim)
+	}
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.SkipTime != "" {
+		params["skip_time"] = r.SkipTime
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLFlushJob) WithContext(v context.Context) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Flush parameters.
+//
+func (f MLFlushJob) WithBody(v io.Reader) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.Body = v
+	}
+}
+
+// WithAdvanceTime - advances time to the given value generating results and updating the model for the advanced interval.
+//
+func (f MLFlushJob) WithAdvanceTime(v string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.AdvanceTime = v
+	}
+}
+
+// WithCalcInterim - calculates interim results for the most recent bucket or all buckets within the latency period.
+//
+func (f MLFlushJob) WithCalcInterim(v bool) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.CalcInterim = &v
+	}
+}
+
+// WithEnd - when used in conjunction with calc_interim, specifies the range of buckets on which to calculate interim results.
+//
+func (f MLFlushJob) WithEnd(v string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.End = v
+	}
+}
+
+// WithSkipTime - skips time to the given value without generating results or updating the model for the skipped interval.
+//
+func (f MLFlushJob) WithSkipTime(v string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.SkipTime = v
+	}
+}
+
+// WithStart - when used in conjunction with calc_interim, specifies the range of buckets on which to calculate interim results.
+//
+func (f MLFlushJob) WithStart(v string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLFlushJob) WithPretty() func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLFlushJob) WithHuman() func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLFlushJob) WithErrorTrace() func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLFlushJob) WithFilterPath(v ...string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLFlushJob) WithHeader(h map[string]string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLFlushJob) WithOpaqueID(s string) func(*MLFlushJobRequest) {
+	return func(r *MLFlushJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.forecast.go b/esapi/api.xpack.ml.forecast.go
new file mode 100644
index 0000000000..41a84fe086
--- /dev/null
+++ b/esapi/api.xpack.ml.forecast.go
@@ -0,0 +1,246 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newMLForecastFunc(t Transport) MLForecast {
+	return func(job_id string, o ...func(*MLForecastRequest)) (*Response, error) {
+		var r = MLForecastRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLForecast - Predicts the future behavior of a time series by using its historical behavior.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-forecast.html.
+//
+type MLForecast func(job_id string, o ...func(*MLForecastRequest)) (*Response, error)
+
+// MLForecastRequest configures the ML Forecast API request.
+//
+type MLForecastRequest struct {
+	JobID string
+
+	Duration       time.Duration
+	ExpiresIn      time.Duration
+	MaxModelMemory string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLForecastRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_forecast"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_forecast")
+
+	params = make(map[string]string)
+
+	if r.Duration != 0 {
+		params["duration"] = formatDuration(r.Duration)
+	}
+
+	if r.ExpiresIn != 0 {
+		params["expires_in"] = formatDuration(r.ExpiresIn)
+	}
+
+	if r.MaxModelMemory != "" {
+		params["max_model_memory"] = r.MaxModelMemory
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLForecast) WithContext(v context.Context) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDuration - the duration of the forecast.
+//
+func (f MLForecast) WithDuration(v time.Duration) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.Duration = v
+	}
+}
+
+// WithExpiresIn - the time interval after which the forecast expires. expired forecasts will be deleted at the first opportunity..
+//
+func (f MLForecast) WithExpiresIn(v time.Duration) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.ExpiresIn = v
+	}
+}
+
+// WithMaxModelMemory - the max memory able to be used by the forecast. default is 20mb..
+//
+func (f MLForecast) WithMaxModelMemory(v string) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.MaxModelMemory = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLForecast) WithPretty() func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLForecast) WithHuman() func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLForecast) WithErrorTrace() func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLForecast) WithFilterPath(v ...string) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLForecast) WithHeader(h map[string]string) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLForecast) WithOpaqueID(s string) func(*MLForecastRequest) {
+	return func(r *MLForecastRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_buckets.go b/esapi/api.xpack.ml.get_buckets.go
new file mode 100644
index 0000000000..26b6e178b5
--- /dev/null
+++ b/esapi/api.xpack.ml.get_buckets.go
@@ -0,0 +1,355 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetBucketsFunc(t Transport) MLGetBuckets {
+	return func(job_id string, o ...func(*MLGetBucketsRequest)) (*Response, error) {
+		var r = MLGetBucketsRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetBuckets - Retrieves anomaly detection job results for one or more buckets.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-bucket.html.
+//
+type MLGetBuckets func(job_id string, o ...func(*MLGetBucketsRequest)) (*Response, error)
+
+// MLGetBucketsRequest configures the ML Get Buckets API request.
+//
+type MLGetBucketsRequest struct {
+	Body io.Reader
+
+	JobID     string
+	Timestamp string
+
+	AnomalyScore   interface{}
+	Desc           *bool
+	End            string
+	ExcludeInterim *bool
+	Expand         *bool
+	From           *int
+	Size           *int
+	Sort           string
+	Start          string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetBucketsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("results") + 1 + len("buckets") + 1 + len(r.Timestamp))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("results")
+	path.WriteString("/")
+	path.WriteString("buckets")
+	if r.Timestamp != "" {
+		path.WriteString("/")
+		path.WriteString(r.Timestamp)
+	}
+
+	params = make(map[string]string)
+
+	if r.AnomalyScore != nil {
+		params["anomaly_score"] = fmt.Sprintf("%v", r.AnomalyScore)
+	}
+
+	if r.Desc != nil {
+		params["desc"] = strconv.FormatBool(*r.Desc)
+	}
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.ExcludeInterim != nil {
+		params["exclude_interim"] = strconv.FormatBool(*r.ExcludeInterim)
+	}
+
+	if r.Expand != nil {
+		params["expand"] = strconv.FormatBool(*r.Expand)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Sort != "" {
+		params["sort"] = r.Sort
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetBuckets) WithContext(v context.Context) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Bucket selection details if not provided in URI.
+//
+func (f MLGetBuckets) WithBody(v io.Reader) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Body = v
+	}
+}
+
+// WithTimestamp - the timestamp of the desired single bucket result.
+//
+func (f MLGetBuckets) WithTimestamp(v string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Timestamp = v
+	}
+}
+
+// WithAnomalyScore - filter for the most anomalous buckets.
+//
+func (f MLGetBuckets) WithAnomalyScore(v interface{}) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.AnomalyScore = v
+	}
+}
+
+// WithDesc - set the sort direction.
+//
+func (f MLGetBuckets) WithDesc(v bool) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Desc = &v
+	}
+}
+
+// WithEnd - end time filter for buckets.
+//
+func (f MLGetBuckets) WithEnd(v string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.End = v
+	}
+}
+
+// WithExcludeInterim - exclude interim results.
+//
+func (f MLGetBuckets) WithExcludeInterim(v bool) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.ExcludeInterim = &v
+	}
+}
+
+// WithExpand - include anomaly records.
+//
+func (f MLGetBuckets) WithExpand(v bool) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Expand = &v
+	}
+}
+
+// WithFrom - skips a number of buckets.
+//
+func (f MLGetBuckets) WithFrom(v int) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of buckets to get.
+//
+func (f MLGetBuckets) WithSize(v int) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithSort - sort buckets by a particular field.
+//
+func (f MLGetBuckets) WithSort(v string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Sort = v
+	}
+}
+
+// WithStart - start time filter for buckets.
+//
+func (f MLGetBuckets) WithStart(v string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetBuckets) WithPretty() func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetBuckets) WithHuman() func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetBuckets) WithErrorTrace() func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetBuckets) WithFilterPath(v ...string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetBuckets) WithHeader(h map[string]string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetBuckets) WithOpaqueID(s string) func(*MLGetBucketsRequest) {
+	return func(r *MLGetBucketsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_calendar_events.go b/esapi/api.xpack.ml.get_calendar_events.go
new file mode 100644
index 0000000000..8e47a5d342
--- /dev/null
+++ b/esapi/api.xpack.ml.get_calendar_events.go
@@ -0,0 +1,273 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetCalendarEventsFunc(t Transport) MLGetCalendarEvents {
+	return func(calendar_id string, o ...func(*MLGetCalendarEventsRequest)) (*Response, error) {
+		var r = MLGetCalendarEventsRequest{CalendarID: calendar_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetCalendarEvents - Retrieves information about the scheduled events in calendars.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar-event.html.
+//
+type MLGetCalendarEvents func(calendar_id string, o ...func(*MLGetCalendarEventsRequest)) (*Response, error)
+
+// MLGetCalendarEventsRequest configures the ML Get Calendar Events API request.
+//
+type MLGetCalendarEventsRequest struct {
+	CalendarID string
+
+	End   interface{}
+	From  *int
+	JobID string
+	Size  *int
+	Start string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetCalendarEventsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID) + 1 + len("events"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+	path.WriteString("/")
+	path.WriteString("events")
+
+	params = make(map[string]string)
+
+	if r.End != nil {
+		params["end"] = fmt.Sprintf("%v", r.End)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.JobID != "" {
+		params["job_id"] = r.JobID
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetCalendarEvents) WithContext(v context.Context) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithEnd - get events before this time.
+//
+func (f MLGetCalendarEvents) WithEnd(v interface{}) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.End = v
+	}
+}
+
+// WithFrom - skips a number of events.
+//
+func (f MLGetCalendarEvents) WithFrom(v int) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.From = &v
+	}
+}
+
+// WithJobID - get events for the job. when this option is used calendar_id must be '_all'.
+//
+func (f MLGetCalendarEvents) WithJobID(v string) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.JobID = v
+	}
+}
+
+// WithSize - specifies a max number of events to get.
+//
+func (f MLGetCalendarEvents) WithSize(v int) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithStart - get events after this time.
+//
+func (f MLGetCalendarEvents) WithStart(v string) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetCalendarEvents) WithPretty() func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetCalendarEvents) WithHuman() func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetCalendarEvents) WithErrorTrace() func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetCalendarEvents) WithFilterPath(v ...string) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetCalendarEvents) WithHeader(h map[string]string) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetCalendarEvents) WithOpaqueID(s string) func(*MLGetCalendarEventsRequest) {
+	return func(r *MLGetCalendarEventsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_calendars.go b/esapi/api.xpack.ml.get_calendars.go
new file mode 100644
index 0000000000..d7a1fc201e
--- /dev/null
+++ b/esapi/api.xpack.ml.get_calendars.go
@@ -0,0 +1,256 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetCalendarsFunc(t Transport) MLGetCalendars {
+	return func(o ...func(*MLGetCalendarsRequest)) (*Response, error) {
+		var r = MLGetCalendarsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetCalendars - Retrieves configuration information for calendars.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-calendar.html.
+//
+type MLGetCalendars func(o ...func(*MLGetCalendarsRequest)) (*Response, error)
+
+// MLGetCalendarsRequest configures the ML Get Calendars API request.
+//
+type MLGetCalendarsRequest struct {
+	Body io.Reader
+
+	CalendarID string
+
+	From *int
+	Size *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetCalendarsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	if r.CalendarID != "" {
+		path.WriteString("/")
+		path.WriteString(r.CalendarID)
+	}
+
+	params = make(map[string]string)
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetCalendars) WithContext(v context.Context) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The from and size parameters optionally sent in the body.
+//
+func (f MLGetCalendars) WithBody(v io.Reader) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.Body = v
+	}
+}
+
+// WithCalendarID - the ID of the calendar to fetch.
+//
+func (f MLGetCalendars) WithCalendarID(v string) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.CalendarID = v
+	}
+}
+
+// WithFrom - skips a number of calendars.
+//
+func (f MLGetCalendars) WithFrom(v int) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of calendars to get.
+//
+func (f MLGetCalendars) WithSize(v int) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetCalendars) WithPretty() func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetCalendars) WithHuman() func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetCalendars) WithErrorTrace() func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetCalendars) WithFilterPath(v ...string) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetCalendars) WithHeader(h map[string]string) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetCalendars) WithOpaqueID(s string) func(*MLGetCalendarsRequest) {
+	return func(r *MLGetCalendarsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_categories.go b/esapi/api.xpack.ml.get_categories.go
new file mode 100644
index 0000000000..531487c0b4
--- /dev/null
+++ b/esapi/api.xpack.ml.get_categories.go
@@ -0,0 +1,278 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetCategoriesFunc(t Transport) MLGetCategories {
+	return func(job_id string, o ...func(*MLGetCategoriesRequest)) (*Response, error) {
+		var r = MLGetCategoriesRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetCategories - Retrieves anomaly detection job results for one or more categories.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-category.html.
+//
+type MLGetCategories func(job_id string, o ...func(*MLGetCategoriesRequest)) (*Response, error)
+
+// MLGetCategoriesRequest configures the ML Get Categories API request.
+//
+type MLGetCategoriesRequest struct {
+	Body io.Reader
+
+	CategoryID *int
+	JobID      string
+
+	From                *int
+	PartitionFieldValue string
+	Size                *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetCategoriesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("results") + 1 + len("categories"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("results")
+	path.WriteString("/")
+	path.WriteString("categories")
+	if r.CategoryID != nil {
+		value := strconv.FormatInt(int64(*r.CategoryID), 10)
+		path.Grow(1 + len(value))
+		path.WriteString("/")
+		path.WriteString(value)
+	}
+
+	params = make(map[string]string)
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.PartitionFieldValue != "" {
+		params["partition_field_value"] = r.PartitionFieldValue
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetCategories) WithContext(v context.Context) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Category selection details if not provided in URI.
+//
+func (f MLGetCategories) WithBody(v io.Reader) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.Body = v
+	}
+}
+
+// WithCategoryID - the identifier of the category definition of interest.
+//
+func (f MLGetCategories) WithCategoryID(v int) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.CategoryID = &v
+	}
+}
+
+// WithFrom - skips a number of categories.
+//
+func (f MLGetCategories) WithFrom(v int) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.From = &v
+	}
+}
+
+// WithPartitionFieldValue - specifies the partition to retrieve categories for. this is optional, and should never be used for jobs where per-partition categorization is disabled..
+//
+func (f MLGetCategories) WithPartitionFieldValue(v string) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.PartitionFieldValue = v
+	}
+}
+
+// WithSize - specifies a max number of categories to get.
+//
+func (f MLGetCategories) WithSize(v int) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetCategories) WithPretty() func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetCategories) WithHuman() func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetCategories) WithErrorTrace() func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetCategories) WithFilterPath(v ...string) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetCategories) WithHeader(h map[string]string) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetCategories) WithOpaqueID(s string) func(*MLGetCategoriesRequest) {
+	return func(r *MLGetCategoriesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_data_frame_analytics.go b/esapi/api.xpack.ml.get_data_frame_analytics.go
new file mode 100644
index 0000000000..3360bcc04e
--- /dev/null
+++ b/esapi/api.xpack.ml.get_data_frame_analytics.go
@@ -0,0 +1,269 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetDataFrameAnalyticsFunc(t Transport) MLGetDataFrameAnalytics {
+	return func(o ...func(*MLGetDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLGetDataFrameAnalyticsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetDataFrameAnalytics - Retrieves configuration information for data frame analytics jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-dfanalytics.html.
+//
+type MLGetDataFrameAnalytics func(o ...func(*MLGetDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLGetDataFrameAnalyticsRequest configures the ML Get Data Frame Analytics API request.
+//
+type MLGetDataFrameAnalyticsRequest struct {
+	ID string
+
+	AllowNoMatch     *bool
+	ExcludeGenerated *bool
+	From             *int
+	Size             *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	if r.ID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetDataFrameAnalytics) WithContext(v context.Context) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithID - the ID of the data frame analytics to fetch.
+//
+func (f MLGetDataFrameAnalytics) WithID(v string) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.ID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no data frame analytics. (this includes `_all` string or when no data frame analytics have been specified).
+//
+func (f MLGetDataFrameAnalytics) WithAllowNoMatch(v bool) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithExcludeGenerated - omits fields that are illegal to set on data frame analytics put.
+//
+func (f MLGetDataFrameAnalytics) WithExcludeGenerated(v bool) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithFrom - skips a number of analytics.
+//
+func (f MLGetDataFrameAnalytics) WithFrom(v int) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of analytics to get.
+//
+func (f MLGetDataFrameAnalytics) WithSize(v int) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetDataFrameAnalytics) WithPretty() func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetDataFrameAnalytics) WithHuman() func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetDataFrameAnalytics) WithErrorTrace() func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetDataFrameAnalytics) WithFilterPath(v ...string) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetDataFrameAnalytics) WithHeader(h map[string]string) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetDataFrameAnalytics) WithOpaqueID(s string) func(*MLGetDataFrameAnalyticsRequest) {
+	return func(r *MLGetDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_data_frame_analytics_stats.go b/esapi/api.xpack.ml.get_data_frame_analytics_stats.go
new file mode 100644
index 0000000000..74d5b4cfd9
--- /dev/null
+++ b/esapi/api.xpack.ml.get_data_frame_analytics_stats.go
@@ -0,0 +1,271 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetDataFrameAnalyticsStatsFunc(t Transport) MLGetDataFrameAnalyticsStats {
+	return func(o ...func(*MLGetDataFrameAnalyticsStatsRequest)) (*Response, error) {
+		var r = MLGetDataFrameAnalyticsStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetDataFrameAnalyticsStats - Retrieves usage information for data frame analytics jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-dfanalytics-stats.html.
+//
+type MLGetDataFrameAnalyticsStats func(o ...func(*MLGetDataFrameAnalyticsStatsRequest)) (*Response, error)
+
+// MLGetDataFrameAnalyticsStatsRequest configures the ML Get Data Frame Analytics Stats API request.
+//
+type MLGetDataFrameAnalyticsStatsRequest struct {
+	ID string
+
+	AllowNoMatch *bool
+	From         *int
+	Size         *int
+	Verbose      *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetDataFrameAnalyticsStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	if r.ID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ID)
+	}
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Verbose != nil {
+		params["verbose"] = strconv.FormatBool(*r.Verbose)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetDataFrameAnalyticsStats) WithContext(v context.Context) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithID - the ID of the data frame analytics stats to fetch.
+//
+func (f MLGetDataFrameAnalyticsStats) WithID(v string) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.ID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no data frame analytics. (this includes `_all` string or when no data frame analytics have been specified).
+//
+func (f MLGetDataFrameAnalyticsStats) WithAllowNoMatch(v bool) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFrom - skips a number of analytics.
+//
+func (f MLGetDataFrameAnalyticsStats) WithFrom(v int) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of analytics to get.
+//
+func (f MLGetDataFrameAnalyticsStats) WithSize(v int) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithVerbose - whether the stats response should be verbose.
+//
+func (f MLGetDataFrameAnalyticsStats) WithVerbose(v bool) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.Verbose = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetDataFrameAnalyticsStats) WithPretty() func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetDataFrameAnalyticsStats) WithHuman() func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetDataFrameAnalyticsStats) WithErrorTrace() func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetDataFrameAnalyticsStats) WithFilterPath(v ...string) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetDataFrameAnalyticsStats) WithHeader(h map[string]string) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetDataFrameAnalyticsStats) WithOpaqueID(s string) func(*MLGetDataFrameAnalyticsStatsRequest) {
+	return func(r *MLGetDataFrameAnalyticsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_datafeed_stats.go b/esapi/api.xpack.ml.get_datafeed_stats.go
new file mode 100644
index 0000000000..51dcf2154b
--- /dev/null
+++ b/esapi/api.xpack.ml.get_datafeed_stats.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetDatafeedStatsFunc(t Transport) MLGetDatafeedStats {
+	return func(o ...func(*MLGetDatafeedStatsRequest)) (*Response, error) {
+		var r = MLGetDatafeedStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetDatafeedStats - Retrieves usage information for datafeeds.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed-stats.html.
+//
+type MLGetDatafeedStats func(o ...func(*MLGetDatafeedStatsRequest)) (*Response, error)
+
+// MLGetDatafeedStatsRequest configures the ML Get Datafeed Stats API request.
+//
+type MLGetDatafeedStatsRequest struct {
+	DatafeedID string
+
+	AllowNoDatafeeds *bool
+	AllowNoMatch     *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetDatafeedStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	if r.DatafeedID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DatafeedID)
+	}
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoDatafeeds != nil {
+		params["allow_no_datafeeds"] = strconv.FormatBool(*r.AllowNoDatafeeds)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetDatafeedStats) WithContext(v context.Context) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDatafeedID - the ID of the datafeeds stats to fetch.
+//
+func (f MLGetDatafeedStats) WithDatafeedID(v string) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.DatafeedID = v
+	}
+}
+
+// WithAllowNoDatafeeds - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLGetDatafeedStats) WithAllowNoDatafeeds(v bool) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.AllowNoDatafeeds = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLGetDatafeedStats) WithAllowNoMatch(v bool) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetDatafeedStats) WithPretty() func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetDatafeedStats) WithHuman() func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetDatafeedStats) WithErrorTrace() func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetDatafeedStats) WithFilterPath(v ...string) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetDatafeedStats) WithHeader(h map[string]string) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetDatafeedStats) WithOpaqueID(s string) func(*MLGetDatafeedStatsRequest) {
+	return func(r *MLGetDatafeedStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_datafeeds.go b/esapi/api.xpack.ml.get_datafeeds.go
new file mode 100644
index 0000000000..bfa3db8a40
--- /dev/null
+++ b/esapi/api.xpack.ml.get_datafeeds.go
@@ -0,0 +1,254 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetDatafeedsFunc(t Transport) MLGetDatafeeds {
+	return func(o ...func(*MLGetDatafeedsRequest)) (*Response, error) {
+		var r = MLGetDatafeedsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetDatafeeds - Retrieves configuration information for datafeeds.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed.html.
+//
+type MLGetDatafeeds func(o ...func(*MLGetDatafeedsRequest)) (*Response, error)
+
+// MLGetDatafeedsRequest configures the ML Get Datafeeds API request.
+//
+type MLGetDatafeedsRequest struct {
+	DatafeedID string
+
+	AllowNoDatafeeds *bool
+	AllowNoMatch     *bool
+	ExcludeGenerated *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetDatafeedsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	if r.DatafeedID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DatafeedID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoDatafeeds != nil {
+		params["allow_no_datafeeds"] = strconv.FormatBool(*r.AllowNoDatafeeds)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetDatafeeds) WithContext(v context.Context) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDatafeedID - the ID of the datafeeds to fetch.
+//
+func (f MLGetDatafeeds) WithDatafeedID(v string) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.DatafeedID = v
+	}
+}
+
+// WithAllowNoDatafeeds - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLGetDatafeeds) WithAllowNoDatafeeds(v bool) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.AllowNoDatafeeds = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLGetDatafeeds) WithAllowNoMatch(v bool) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithExcludeGenerated - omits fields that are illegal to set on datafeed put.
+//
+func (f MLGetDatafeeds) WithExcludeGenerated(v bool) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetDatafeeds) WithPretty() func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetDatafeeds) WithHuman() func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetDatafeeds) WithErrorTrace() func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetDatafeeds) WithFilterPath(v ...string) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetDatafeeds) WithHeader(h map[string]string) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetDatafeeds) WithOpaqueID(s string) func(*MLGetDatafeedsRequest) {
+	return func(r *MLGetDatafeedsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_filters.go b/esapi/api.xpack.ml.get_filters.go
new file mode 100644
index 0000000000..71fb2b5e9d
--- /dev/null
+++ b/esapi/api.xpack.ml.get_filters.go
@@ -0,0 +1,241 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetFiltersFunc(t Transport) MLGetFilters {
+	return func(o ...func(*MLGetFiltersRequest)) (*Response, error) {
+		var r = MLGetFiltersRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetFilters - Retrieves filters.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-filter.html.
+//
+type MLGetFilters func(o ...func(*MLGetFiltersRequest)) (*Response, error)
+
+// MLGetFiltersRequest configures the ML Get Filters API request.
+//
+type MLGetFiltersRequest struct {
+	FilterID string
+
+	From *int
+	Size *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetFiltersRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("filters") + 1 + len(r.FilterID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("filters")
+	if r.FilterID != "" {
+		path.WriteString("/")
+		path.WriteString(r.FilterID)
+	}
+
+	params = make(map[string]string)
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetFilters) WithContext(v context.Context) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.ctx = v
+	}
+}
+
+// WithFilterID - the ID of the filter to fetch.
+//
+func (f MLGetFilters) WithFilterID(v string) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.FilterID = v
+	}
+}
+
+// WithFrom - skips a number of filters.
+//
+func (f MLGetFilters) WithFrom(v int) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of filters to get.
+//
+func (f MLGetFilters) WithSize(v int) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetFilters) WithPretty() func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetFilters) WithHuman() func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetFilters) WithErrorTrace() func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetFilters) WithFilterPath(v ...string) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetFilters) WithHeader(h map[string]string) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetFilters) WithOpaqueID(s string) func(*MLGetFiltersRequest) {
+	return func(r *MLGetFiltersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_influencers.go b/esapi/api.xpack.ml.get_influencers.go
new file mode 100644
index 0000000000..d8819576ab
--- /dev/null
+++ b/esapi/api.xpack.ml.get_influencers.go
@@ -0,0 +1,329 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetInfluencersFunc(t Transport) MLGetInfluencers {
+	return func(job_id string, o ...func(*MLGetInfluencersRequest)) (*Response, error) {
+		var r = MLGetInfluencersRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetInfluencers - Retrieves anomaly detection job results for one or more influencers.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-influencer.html.
+//
+type MLGetInfluencers func(job_id string, o ...func(*MLGetInfluencersRequest)) (*Response, error)
+
+// MLGetInfluencersRequest configures the ML Get Influencers API request.
+//
+type MLGetInfluencersRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	Desc            *bool
+	End             string
+	ExcludeInterim  *bool
+	From            *int
+	InfluencerScore interface{}
+	Size            *int
+	Sort            string
+	Start           string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetInfluencersRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("results") + 1 + len("influencers"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("results")
+	path.WriteString("/")
+	path.WriteString("influencers")
+
+	params = make(map[string]string)
+
+	if r.Desc != nil {
+		params["desc"] = strconv.FormatBool(*r.Desc)
+	}
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.ExcludeInterim != nil {
+		params["exclude_interim"] = strconv.FormatBool(*r.ExcludeInterim)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.InfluencerScore != nil {
+		params["influencer_score"] = fmt.Sprintf("%v", r.InfluencerScore)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Sort != "" {
+		params["sort"] = r.Sort
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetInfluencers) WithContext(v context.Context) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Influencer selection criteria.
+//
+func (f MLGetInfluencers) WithBody(v io.Reader) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Body = v
+	}
+}
+
+// WithDesc - whether the results should be sorted in decending order.
+//
+func (f MLGetInfluencers) WithDesc(v bool) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Desc = &v
+	}
+}
+
+// WithEnd - end timestamp for the requested influencers.
+//
+func (f MLGetInfluencers) WithEnd(v string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.End = v
+	}
+}
+
+// WithExcludeInterim - exclude interim results.
+//
+func (f MLGetInfluencers) WithExcludeInterim(v bool) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.ExcludeInterim = &v
+	}
+}
+
+// WithFrom - skips a number of influencers.
+//
+func (f MLGetInfluencers) WithFrom(v int) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.From = &v
+	}
+}
+
+// WithInfluencerScore - influencer score threshold for the requested influencers.
+//
+func (f MLGetInfluencers) WithInfluencerScore(v interface{}) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.InfluencerScore = v
+	}
+}
+
+// WithSize - specifies a max number of influencers to get.
+//
+func (f MLGetInfluencers) WithSize(v int) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Size = &v
+	}
+}
+
+// WithSort - sort field for the requested influencers.
+//
+func (f MLGetInfluencers) WithSort(v string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Sort = v
+	}
+}
+
+// WithStart - start timestamp for the requested influencers.
+//
+func (f MLGetInfluencers) WithStart(v string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetInfluencers) WithPretty() func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetInfluencers) WithHuman() func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetInfluencers) WithErrorTrace() func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetInfluencers) WithFilterPath(v ...string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetInfluencers) WithHeader(h map[string]string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetInfluencers) WithOpaqueID(s string) func(*MLGetInfluencersRequest) {
+	return func(r *MLGetInfluencersRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_job_stats.go b/esapi/api.xpack.ml.get_job_stats.go
new file mode 100644
index 0000000000..013b29b7a9
--- /dev/null
+++ b/esapi/api.xpack.ml.get_job_stats.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetJobStatsFunc(t Transport) MLGetJobStats {
+	return func(o ...func(*MLGetJobStatsRequest)) (*Response, error) {
+		var r = MLGetJobStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetJobStats - Retrieves usage information for anomaly detection jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-job-stats.html.
+//
+type MLGetJobStats func(o ...func(*MLGetJobStatsRequest)) (*Response, error)
+
+// MLGetJobStatsRequest configures the ML Get Job Stats API request.
+//
+type MLGetJobStatsRequest struct {
+	JobID string
+
+	AllowNoJobs  *bool
+	AllowNoMatch *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetJobStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	if r.JobID != "" {
+		path.WriteString("/")
+		path.WriteString(r.JobID)
+	}
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoJobs != nil {
+		params["allow_no_jobs"] = strconv.FormatBool(*r.AllowNoJobs)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetJobStats) WithContext(v context.Context) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithJobID - the ID of the jobs stats to fetch.
+//
+func (f MLGetJobStats) WithJobID(v string) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.JobID = v
+	}
+}
+
+// WithAllowNoJobs - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetJobStats) WithAllowNoJobs(v bool) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.AllowNoJobs = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetJobStats) WithAllowNoMatch(v bool) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetJobStats) WithPretty() func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetJobStats) WithHuman() func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetJobStats) WithErrorTrace() func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetJobStats) WithFilterPath(v ...string) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetJobStats) WithHeader(h map[string]string) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetJobStats) WithOpaqueID(s string) func(*MLGetJobStatsRequest) {
+	return func(r *MLGetJobStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_jobs.go b/esapi/api.xpack.ml.get_jobs.go
new file mode 100644
index 0000000000..006d15279c
--- /dev/null
+++ b/esapi/api.xpack.ml.get_jobs.go
@@ -0,0 +1,254 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetJobsFunc(t Transport) MLGetJobs {
+	return func(o ...func(*MLGetJobsRequest)) (*Response, error) {
+		var r = MLGetJobsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetJobs - Retrieves configuration information for anomaly detection jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-job.html.
+//
+type MLGetJobs func(o ...func(*MLGetJobsRequest)) (*Response, error)
+
+// MLGetJobsRequest configures the ML Get Jobs API request.
+//
+type MLGetJobsRequest struct {
+	JobID string
+
+	AllowNoJobs      *bool
+	AllowNoMatch     *bool
+	ExcludeGenerated *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetJobsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	if r.JobID != "" {
+		path.WriteString("/")
+		path.WriteString(r.JobID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoJobs != nil {
+		params["allow_no_jobs"] = strconv.FormatBool(*r.AllowNoJobs)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetJobs) WithContext(v context.Context) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithJobID - the ID of the jobs to fetch.
+//
+func (f MLGetJobs) WithJobID(v string) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.JobID = v
+	}
+}
+
+// WithAllowNoJobs - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetJobs) WithAllowNoJobs(v bool) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.AllowNoJobs = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetJobs) WithAllowNoMatch(v bool) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithExcludeGenerated - omits fields that are illegal to set on job put.
+//
+func (f MLGetJobs) WithExcludeGenerated(v bool) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetJobs) WithPretty() func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetJobs) WithHuman() func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetJobs) WithErrorTrace() func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetJobs) WithFilterPath(v ...string) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetJobs) WithHeader(h map[string]string) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetJobs) WithOpaqueID(s string) func(*MLGetJobsRequest) {
+	return func(r *MLGetJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_model_snapshots.go b/esapi/api.xpack.ml.get_model_snapshots.go
new file mode 100644
index 0000000000..1aad0db993
--- /dev/null
+++ b/esapi/api.xpack.ml.get_model_snapshots.go
@@ -0,0 +1,314 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetModelSnapshotsFunc(t Transport) MLGetModelSnapshots {
+	return func(job_id string, o ...func(*MLGetModelSnapshotsRequest)) (*Response, error) {
+		var r = MLGetModelSnapshotsRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetModelSnapshots - Retrieves information about model snapshots.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-snapshot.html.
+//
+type MLGetModelSnapshots func(job_id string, o ...func(*MLGetModelSnapshotsRequest)) (*Response, error)
+
+// MLGetModelSnapshotsRequest configures the ML Get Model Snapshots API request.
+//
+type MLGetModelSnapshotsRequest struct {
+	Body io.Reader
+
+	JobID      string
+	SnapshotID string
+
+	Desc  *bool
+	End   interface{}
+	From  *int
+	Size  *int
+	Sort  string
+	Start interface{}
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetModelSnapshotsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("model_snapshots") + 1 + len(r.SnapshotID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("model_snapshots")
+	if r.SnapshotID != "" {
+		path.WriteString("/")
+		path.WriteString(r.SnapshotID)
+	}
+
+	params = make(map[string]string)
+
+	if r.Desc != nil {
+		params["desc"] = strconv.FormatBool(*r.Desc)
+	}
+
+	if r.End != nil {
+		params["end"] = fmt.Sprintf("%v", r.End)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Sort != "" {
+		params["sort"] = r.Sort
+	}
+
+	if r.Start != nil {
+		params["start"] = fmt.Sprintf("%v", r.Start)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetModelSnapshots) WithContext(v context.Context) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Model snapshot selection criteria.
+//
+func (f MLGetModelSnapshots) WithBody(v io.Reader) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Body = v
+	}
+}
+
+// WithSnapshotID - the ID of the snapshot to fetch.
+//
+func (f MLGetModelSnapshots) WithSnapshotID(v string) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.SnapshotID = v
+	}
+}
+
+// WithDesc - true if the results should be sorted in descending order.
+//
+func (f MLGetModelSnapshots) WithDesc(v bool) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Desc = &v
+	}
+}
+
+// WithEnd - the filter 'end' query parameter.
+//
+func (f MLGetModelSnapshots) WithEnd(v interface{}) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.End = v
+	}
+}
+
+// WithFrom - skips a number of documents.
+//
+func (f MLGetModelSnapshots) WithFrom(v int) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - the default number of documents returned in queries as a string..
+//
+func (f MLGetModelSnapshots) WithSize(v int) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithSort - name of the field to sort on.
+//
+func (f MLGetModelSnapshots) WithSort(v string) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Sort = v
+	}
+}
+
+// WithStart - the filter 'start' query parameter.
+//
+func (f MLGetModelSnapshots) WithStart(v interface{}) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetModelSnapshots) WithPretty() func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetModelSnapshots) WithHuman() func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetModelSnapshots) WithErrorTrace() func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetModelSnapshots) WithFilterPath(v ...string) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetModelSnapshots) WithHeader(h map[string]string) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetModelSnapshots) WithOpaqueID(s string) func(*MLGetModelSnapshotsRequest) {
+	return func(r *MLGetModelSnapshotsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_overall_buckets.go b/esapi/api.xpack.ml.get_overall_buckets.go
new file mode 100644
index 0000000000..1a4c1d5006
--- /dev/null
+++ b/esapi/api.xpack.ml.get_overall_buckets.go
@@ -0,0 +1,329 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetOverallBucketsFunc(t Transport) MLGetOverallBuckets {
+	return func(job_id string, o ...func(*MLGetOverallBucketsRequest)) (*Response, error) {
+		var r = MLGetOverallBucketsRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetOverallBuckets - Retrieves overall bucket results that summarize the bucket results of multiple anomaly detection jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-overall-buckets.html.
+//
+type MLGetOverallBuckets func(job_id string, o ...func(*MLGetOverallBucketsRequest)) (*Response, error)
+
+// MLGetOverallBucketsRequest configures the ML Get Overall Buckets API request.
+//
+type MLGetOverallBucketsRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	AllowNoJobs    *bool
+	AllowNoMatch   *bool
+	BucketSpan     string
+	End            string
+	ExcludeInterim *bool
+	OverallScore   interface{}
+	Start          string
+	TopN           *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetOverallBucketsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("results") + 1 + len("overall_buckets"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("results")
+	path.WriteString("/")
+	path.WriteString("overall_buckets")
+
+	params = make(map[string]string)
+
+	if r.AllowNoJobs != nil {
+		params["allow_no_jobs"] = strconv.FormatBool(*r.AllowNoJobs)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.BucketSpan != "" {
+		params["bucket_span"] = r.BucketSpan
+	}
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.ExcludeInterim != nil {
+		params["exclude_interim"] = strconv.FormatBool(*r.ExcludeInterim)
+	}
+
+	if r.OverallScore != nil {
+		params["overall_score"] = fmt.Sprintf("%v", r.OverallScore)
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.TopN != nil {
+		params["top_n"] = strconv.FormatInt(int64(*r.TopN), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetOverallBuckets) WithContext(v context.Context) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Overall bucket selection details if not provided in URI.
+//
+func (f MLGetOverallBuckets) WithBody(v io.Reader) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.Body = v
+	}
+}
+
+// WithAllowNoJobs - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetOverallBuckets) WithAllowNoJobs(v bool) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.AllowNoJobs = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no jobs. (this includes `_all` string or when no jobs have been specified).
+//
+func (f MLGetOverallBuckets) WithAllowNoMatch(v bool) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithBucketSpan - the span of the overall buckets. defaults to the longest job bucket_span.
+//
+func (f MLGetOverallBuckets) WithBucketSpan(v string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.BucketSpan = v
+	}
+}
+
+// WithEnd - returns overall buckets with timestamps earlier than this time.
+//
+func (f MLGetOverallBuckets) WithEnd(v string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.End = v
+	}
+}
+
+// WithExcludeInterim - if true overall buckets that include interim buckets will be excluded.
+//
+func (f MLGetOverallBuckets) WithExcludeInterim(v bool) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.ExcludeInterim = &v
+	}
+}
+
+// WithOverallScore - returns overall buckets with overall scores higher than this value.
+//
+func (f MLGetOverallBuckets) WithOverallScore(v interface{}) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.OverallScore = v
+	}
+}
+
+// WithStart - returns overall buckets with timestamps after this time.
+//
+func (f MLGetOverallBuckets) WithStart(v string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.Start = v
+	}
+}
+
+// WithTopN - the number of top job bucket scores to be used in the overall_score calculation.
+//
+func (f MLGetOverallBuckets) WithTopN(v int) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.TopN = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetOverallBuckets) WithPretty() func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetOverallBuckets) WithHuman() func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetOverallBuckets) WithErrorTrace() func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetOverallBuckets) WithFilterPath(v ...string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetOverallBuckets) WithHeader(h map[string]string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetOverallBuckets) WithOpaqueID(s string) func(*MLGetOverallBucketsRequest) {
+	return func(r *MLGetOverallBucketsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_records.go b/esapi/api.xpack.ml.get_records.go
new file mode 100644
index 0000000000..c40d2230ae
--- /dev/null
+++ b/esapi/api.xpack.ml.get_records.go
@@ -0,0 +1,329 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetRecordsFunc(t Transport) MLGetRecords {
+	return func(job_id string, o ...func(*MLGetRecordsRequest)) (*Response, error) {
+		var r = MLGetRecordsRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetRecords - Retrieves anomaly records for an anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-record.html.
+//
+type MLGetRecords func(job_id string, o ...func(*MLGetRecordsRequest)) (*Response, error)
+
+// MLGetRecordsRequest configures the ML Get Records API request.
+//
+type MLGetRecordsRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	Desc           *bool
+	End            string
+	ExcludeInterim *bool
+	From           *int
+	RecordScore    interface{}
+	Size           *int
+	Sort           string
+	Start          string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetRecordsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("results") + 1 + len("records"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("results")
+	path.WriteString("/")
+	path.WriteString("records")
+
+	params = make(map[string]string)
+
+	if r.Desc != nil {
+		params["desc"] = strconv.FormatBool(*r.Desc)
+	}
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.ExcludeInterim != nil {
+		params["exclude_interim"] = strconv.FormatBool(*r.ExcludeInterim)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.RecordScore != nil {
+		params["record_score"] = fmt.Sprintf("%v", r.RecordScore)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Sort != "" {
+		params["sort"] = r.Sort
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetRecords) WithContext(v context.Context) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Record selection criteria.
+//
+func (f MLGetRecords) WithBody(v io.Reader) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Body = v
+	}
+}
+
+// WithDesc - set the sort direction.
+//
+func (f MLGetRecords) WithDesc(v bool) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Desc = &v
+	}
+}
+
+// WithEnd - end time filter for records.
+//
+func (f MLGetRecords) WithEnd(v string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.End = v
+	}
+}
+
+// WithExcludeInterim - exclude interim results.
+//
+func (f MLGetRecords) WithExcludeInterim(v bool) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.ExcludeInterim = &v
+	}
+}
+
+// WithFrom - skips a number of records.
+//
+func (f MLGetRecords) WithFrom(v int) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.From = &v
+	}
+}
+
+// WithRecordScore - returns records with anomaly scores greater or equal than this value.
+//
+func (f MLGetRecords) WithRecordScore(v interface{}) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.RecordScore = v
+	}
+}
+
+// WithSize - specifies a max number of records to get.
+//
+func (f MLGetRecords) WithSize(v int) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithSort - sort records by a particular field.
+//
+func (f MLGetRecords) WithSort(v string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Sort = v
+	}
+}
+
+// WithStart - start time filter for records.
+//
+func (f MLGetRecords) WithStart(v string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Start = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetRecords) WithPretty() func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetRecords) WithHuman() func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetRecords) WithErrorTrace() func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetRecords) WithFilterPath(v ...string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetRecords) WithHeader(h map[string]string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetRecords) WithOpaqueID(s string) func(*MLGetRecordsRequest) {
+	return func(r *MLGetRecordsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_trained_models.go b/esapi/api.xpack.ml.get_trained_models.go
new file mode 100644
index 0000000000..9f9950892b
--- /dev/null
+++ b/esapi/api.xpack.ml.get_trained_models.go
@@ -0,0 +1,319 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetTrainedModelsFunc(t Transport) MLGetTrainedModels {
+	return func(o ...func(*MLGetTrainedModelsRequest)) (*Response, error) {
+		var r = MLGetTrainedModelsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetTrainedModels - Retrieves configuration information for a trained inference model.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-trained-models.html.
+//
+type MLGetTrainedModels func(o ...func(*MLGetTrainedModelsRequest)) (*Response, error)
+
+// MLGetTrainedModelsRequest configures the ML Get Trained Models API request.
+//
+type MLGetTrainedModelsRequest struct {
+	ModelID string
+
+	AllowNoMatch           *bool
+	DecompressDefinition   *bool
+	ExcludeGenerated       *bool
+	From                   *int
+	Include                string
+	IncludeModelDefinition *bool
+	Size                   *int
+	Tags                   []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetTrainedModelsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	if r.ModelID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ModelID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.DecompressDefinition != nil {
+		params["decompress_definition"] = strconv.FormatBool(*r.DecompressDefinition)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Include != "" {
+		params["include"] = r.Include
+	}
+
+	if r.IncludeModelDefinition != nil {
+		params["include_model_definition"] = strconv.FormatBool(*r.IncludeModelDefinition)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if len(r.Tags) > 0 {
+		params["tags"] = strings.Join(r.Tags, ",")
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetTrainedModels) WithContext(v context.Context) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithModelID - the ID of the trained models to fetch.
+//
+func (f MLGetTrainedModels) WithModelID(v string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.ModelID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no trained models. (this includes `_all` string or when no trained models have been specified).
+//
+func (f MLGetTrainedModels) WithAllowNoMatch(v bool) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithDecompressDefinition - should the model definition be decompressed into valid json or returned in a custom compressed format. defaults to true..
+//
+func (f MLGetTrainedModels) WithDecompressDefinition(v bool) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.DecompressDefinition = &v
+	}
+}
+
+// WithExcludeGenerated - omits fields that are illegal to set on model put.
+//
+func (f MLGetTrainedModels) WithExcludeGenerated(v bool) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithFrom - skips a number of trained models.
+//
+func (f MLGetTrainedModels) WithFrom(v int) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.From = &v
+	}
+}
+
+// WithInclude - a comma-separate list of fields to optionally include. valid options are 'definition' and 'total_feature_importance'. default is none..
+//
+func (f MLGetTrainedModels) WithInclude(v string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.Include = v
+	}
+}
+
+// WithIncludeModelDefinition - should the full model definition be included in the results. these definitions can be large. so be cautious when including them. defaults to false..
+//
+func (f MLGetTrainedModels) WithIncludeModelDefinition(v bool) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.IncludeModelDefinition = &v
+	}
+}
+
+// WithSize - specifies a max number of trained models to get.
+//
+func (f MLGetTrainedModels) WithSize(v int) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithTags - a list of tags that the model must have..
+//
+func (f MLGetTrainedModels) WithTags(v ...string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.Tags = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetTrainedModels) WithPretty() func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetTrainedModels) WithHuman() func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetTrainedModels) WithErrorTrace() func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetTrainedModels) WithFilterPath(v ...string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetTrainedModels) WithHeader(h map[string]string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetTrainedModels) WithOpaqueID(s string) func(*MLGetTrainedModelsRequest) {
+	return func(r *MLGetTrainedModelsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.get_trained_models_stats.go b/esapi/api.xpack.ml.get_trained_models_stats.go
new file mode 100644
index 0000000000..18eb93ceb8
--- /dev/null
+++ b/esapi/api.xpack.ml.get_trained_models_stats.go
@@ -0,0 +1,256 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLGetTrainedModelsStatsFunc(t Transport) MLGetTrainedModelsStats {
+	return func(o ...func(*MLGetTrainedModelsStatsRequest)) (*Response, error) {
+		var r = MLGetTrainedModelsStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLGetTrainedModelsStats - Retrieves usage information for trained inference models.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-trained-models-stats.html.
+//
+type MLGetTrainedModelsStats func(o ...func(*MLGetTrainedModelsStatsRequest)) (*Response, error)
+
+// MLGetTrainedModelsStatsRequest configures the ML Get Trained Models Stats API request.
+//
+type MLGetTrainedModelsStatsRequest struct {
+	ModelID string
+
+	AllowNoMatch *bool
+	From         *int
+	Size         *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLGetTrainedModelsStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	if r.ModelID != "" {
+		path.WriteString("/")
+		path.WriteString(r.ModelID)
+	}
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLGetTrainedModelsStats) WithContext(v context.Context) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithModelID - the ID of the trained models stats to fetch.
+//
+func (f MLGetTrainedModelsStats) WithModelID(v string) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.ModelID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no trained models. (this includes `_all` string or when no trained models have been specified).
+//
+func (f MLGetTrainedModelsStats) WithAllowNoMatch(v bool) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFrom - skips a number of trained models.
+//
+func (f MLGetTrainedModelsStats) WithFrom(v int) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of trained models to get.
+//
+func (f MLGetTrainedModelsStats) WithSize(v int) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLGetTrainedModelsStats) WithPretty() func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLGetTrainedModelsStats) WithHuman() func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLGetTrainedModelsStats) WithErrorTrace() func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLGetTrainedModelsStats) WithFilterPath(v ...string) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLGetTrainedModelsStats) WithHeader(h map[string]string) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLGetTrainedModelsStats) WithOpaqueID(s string) func(*MLGetTrainedModelsStatsRequest) {
+	return func(r *MLGetTrainedModelsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.info.go b/esapi/api.xpack.ml.info.go
new file mode 100644
index 0000000000..a36c411917
--- /dev/null
+++ b/esapi/api.xpack.ml.info.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLInfoFunc(t Transport) MLInfo {
+	return func(o ...func(*MLInfoRequest)) (*Response, error) {
+		var r = MLInfoRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLInfo - Returns defaults and limits used by machine learning.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-ml-info.html.
+//
+type MLInfo func(o ...func(*MLInfoRequest)) (*Response, error)
+
+// MLInfoRequest configures the ML Info API request.
+//
+type MLInfoRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLInfoRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_ml/info"))
+	path.WriteString("/_ml/info")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLInfo) WithContext(v context.Context) func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLInfo) WithPretty() func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLInfo) WithHuman() func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLInfo) WithErrorTrace() func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLInfo) WithFilterPath(v ...string) func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLInfo) WithHeader(h map[string]string) func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLInfo) WithOpaqueID(s string) func(*MLInfoRequest) {
+	return func(r *MLInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.open_job.go b/esapi/api.xpack.ml.open_job.go
new file mode 100644
index 0000000000..bb731dd54b
--- /dev/null
+++ b/esapi/api.xpack.ml.open_job.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLOpenJobFunc(t Transport) MLOpenJob {
+	return func(job_id string, o ...func(*MLOpenJobRequest)) (*Response, error) {
+		var r = MLOpenJobRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLOpenJob - Opens one or more anomaly detection jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-open-job.html.
+//
+type MLOpenJob func(job_id string, o ...func(*MLOpenJobRequest)) (*Response, error)
+
+// MLOpenJobRequest configures the ML Open Job API request.
+//
+type MLOpenJobRequest struct {
+	JobID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLOpenJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_open"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_open")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLOpenJob) WithContext(v context.Context) func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLOpenJob) WithPretty() func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLOpenJob) WithHuman() func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLOpenJob) WithErrorTrace() func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLOpenJob) WithFilterPath(v ...string) func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLOpenJob) WithHeader(h map[string]string) func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLOpenJob) WithOpaqueID(s string) func(*MLOpenJobRequest) {
+	return func(r *MLOpenJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.post_calendar_events.go b/esapi/api.xpack.ml.post_calendar_events.go
new file mode 100644
index 0000000000..944354a835
--- /dev/null
+++ b/esapi/api.xpack.ml.post_calendar_events.go
@@ -0,0 +1,212 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPostCalendarEventsFunc(t Transport) MLPostCalendarEvents {
+	return func(calendar_id string, body io.Reader, o ...func(*MLPostCalendarEventsRequest)) (*Response, error) {
+		var r = MLPostCalendarEventsRequest{CalendarID: calendar_id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPostCalendarEvents - Posts scheduled events in a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-post-calendar-event.html.
+//
+type MLPostCalendarEvents func(calendar_id string, body io.Reader, o ...func(*MLPostCalendarEventsRequest)) (*Response, error)
+
+// MLPostCalendarEventsRequest configures the ML Post Calendar Events API request.
+//
+type MLPostCalendarEventsRequest struct {
+	Body io.Reader
+
+	CalendarID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPostCalendarEventsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID) + 1 + len("events"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+	path.WriteString("/")
+	path.WriteString("events")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPostCalendarEvents) WithContext(v context.Context) func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPostCalendarEvents) WithPretty() func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPostCalendarEvents) WithHuman() func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPostCalendarEvents) WithErrorTrace() func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPostCalendarEvents) WithFilterPath(v ...string) func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPostCalendarEvents) WithHeader(h map[string]string) func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPostCalendarEvents) WithOpaqueID(s string) func(*MLPostCalendarEventsRequest) {
+	return func(r *MLPostCalendarEventsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.post_data.go b/esapi/api.xpack.ml.post_data.go
new file mode 100644
index 0000000000..e021f28cdd
--- /dev/null
+++ b/esapi/api.xpack.ml.post_data.go
@@ -0,0 +1,239 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPostDataFunc(t Transport) MLPostData {
+	return func(job_id string, body io.Reader, o ...func(*MLPostDataRequest)) (*Response, error) {
+		var r = MLPostDataRequest{JobID: job_id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPostData - Sends data to an anomaly detection job for analysis.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-post-data.html.
+//
+type MLPostData func(job_id string, body io.Reader, o ...func(*MLPostDataRequest)) (*Response, error)
+
+// MLPostDataRequest configures the ML Post Data API request.
+//
+type MLPostDataRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	ResetEnd   string
+	ResetStart string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPostDataRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_data"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_data")
+
+	params = make(map[string]string)
+
+	if r.ResetEnd != "" {
+		params["reset_end"] = r.ResetEnd
+	}
+
+	if r.ResetStart != "" {
+		params["reset_start"] = r.ResetStart
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPostData) WithContext(v context.Context) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.ctx = v
+	}
+}
+
+// WithResetEnd - optional parameter to specify the end of the bucket resetting range.
+//
+func (f MLPostData) WithResetEnd(v string) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.ResetEnd = v
+	}
+}
+
+// WithResetStart - optional parameter to specify the start of the bucket resetting range.
+//
+func (f MLPostData) WithResetStart(v string) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.ResetStart = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPostData) WithPretty() func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPostData) WithHuman() func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPostData) WithErrorTrace() func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPostData) WithFilterPath(v ...string) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPostData) WithHeader(h map[string]string) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPostData) WithOpaqueID(s string) func(*MLPostDataRequest) {
+	return func(r *MLPostDataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.preview_data_frame_analytics.go b/esapi/api.xpack.ml.preview_data_frame_analytics.go
new file mode 100644
index 0000000000..4a26e9690d
--- /dev/null
+++ b/esapi/api.xpack.ml.preview_data_frame_analytics.go
@@ -0,0 +1,232 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPreviewDataFrameAnalyticsFunc(t Transport) MLPreviewDataFrameAnalytics {
+	return func(o ...func(*MLPreviewDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLPreviewDataFrameAnalyticsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPreviewDataFrameAnalytics - Previews that will be analyzed given a data frame analytics config.
+//
+// See full documentation at http://www.elastic.co/guide/en/elasticsearch/reference/current/preview-dfanalytics.html.
+//
+type MLPreviewDataFrameAnalytics func(o ...func(*MLPreviewDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLPreviewDataFrameAnalyticsRequest configures the ML Preview Data Frame Analytics API request.
+//
+type MLPreviewDataFrameAnalyticsRequest struct {
+	DocumentID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPreviewDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.DocumentID) + 1 + len("_preview"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	if r.DocumentID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentID)
+	}
+	path.WriteString("/")
+	path.WriteString("_preview")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPreviewDataFrameAnalytics) WithContext(v context.Context) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The data frame analytics config to preview.
+//
+func (f MLPreviewDataFrameAnalytics) WithBody(v io.Reader) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.Body = v
+	}
+}
+
+// WithDocumentID - the ID of the data frame analytics to preview.
+//
+func (f MLPreviewDataFrameAnalytics) WithDocumentID(v string) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.DocumentID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPreviewDataFrameAnalytics) WithPretty() func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPreviewDataFrameAnalytics) WithHuman() func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPreviewDataFrameAnalytics) WithErrorTrace() func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPreviewDataFrameAnalytics) WithFilterPath(v ...string) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPreviewDataFrameAnalytics) WithHeader(h map[string]string) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPreviewDataFrameAnalytics) WithOpaqueID(s string) func(*MLPreviewDataFrameAnalyticsRequest) {
+	return func(r *MLPreviewDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.preview_datafeed.go b/esapi/api.xpack.ml.preview_datafeed.go
new file mode 100644
index 0000000000..5957bfb350
--- /dev/null
+++ b/esapi/api.xpack.ml.preview_datafeed.go
@@ -0,0 +1,230 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPreviewDatafeedFunc(t Transport) MLPreviewDatafeed {
+	return func(o ...func(*MLPreviewDatafeedRequest)) (*Response, error) {
+		var r = MLPreviewDatafeedRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPreviewDatafeed - Previews a datafeed.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-preview-datafeed.html.
+//
+type MLPreviewDatafeed func(o ...func(*MLPreviewDatafeedRequest)) (*Response, error)
+
+// MLPreviewDatafeedRequest configures the ML Preview Datafeed API request.
+//
+type MLPreviewDatafeedRequest struct {
+	Body io.Reader
+
+	DatafeedID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPreviewDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID) + 1 + len("_preview"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	if r.DatafeedID != "" {
+		path.WriteString("/")
+		path.WriteString(r.DatafeedID)
+	}
+	path.WriteString("/")
+	path.WriteString("_preview")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPreviewDatafeed) WithContext(v context.Context) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The datafeed config and job config with which to execute the preview.
+//
+func (f MLPreviewDatafeed) WithBody(v io.Reader) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.Body = v
+	}
+}
+
+// WithDatafeedID - the ID of the datafeed to preview.
+//
+func (f MLPreviewDatafeed) WithDatafeedID(v string) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.DatafeedID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPreviewDatafeed) WithPretty() func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPreviewDatafeed) WithHuman() func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPreviewDatafeed) WithErrorTrace() func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPreviewDatafeed) WithFilterPath(v ...string) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPreviewDatafeed) WithHeader(h map[string]string) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPreviewDatafeed) WithOpaqueID(s string) func(*MLPreviewDatafeedRequest) {
+	return func(r *MLPreviewDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_calendar.go b/esapi/api.xpack.ml.put_calendar.go
new file mode 100644
index 0000000000..388d618a84
--- /dev/null
+++ b/esapi/api.xpack.ml.put_calendar.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPutCalendarFunc(t Transport) MLPutCalendar {
+	return func(calendar_id string, o ...func(*MLPutCalendarRequest)) (*Response, error) {
+		var r = MLPutCalendarRequest{CalendarID: calendar_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutCalendar - Instantiates a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-calendar.html.
+//
+type MLPutCalendar func(calendar_id string, o ...func(*MLPutCalendarRequest)) (*Response, error)
+
+// MLPutCalendarRequest configures the ML Put Calendar API request.
+//
+type MLPutCalendarRequest struct {
+	Body io.Reader
+
+	CalendarID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutCalendarRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutCalendar) WithContext(v context.Context) func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The calendar details.
+//
+func (f MLPutCalendar) WithBody(v io.Reader) func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutCalendar) WithPretty() func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutCalendar) WithHuman() func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutCalendar) WithErrorTrace() func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutCalendar) WithFilterPath(v ...string) func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutCalendar) WithHeader(h map[string]string) func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutCalendar) WithOpaqueID(s string) func(*MLPutCalendarRequest) {
+	return func(r *MLPutCalendarRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_calendar_job.go b/esapi/api.xpack.ml.put_calendar_job.go
new file mode 100644
index 0000000000..181176fabc
--- /dev/null
+++ b/esapi/api.xpack.ml.put_calendar_job.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newMLPutCalendarJobFunc(t Transport) MLPutCalendarJob {
+	return func(calendar_id string, job_id string, o ...func(*MLPutCalendarJobRequest)) (*Response, error) {
+		var r = MLPutCalendarJobRequest{CalendarID: calendar_id, JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutCalendarJob - Adds an anomaly detection job to a calendar.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-calendar-job.html.
+//
+type MLPutCalendarJob func(calendar_id string, job_id string, o ...func(*MLPutCalendarJobRequest)) (*Response, error)
+
+// MLPutCalendarJobRequest configures the ML Put Calendar Job API request.
+//
+type MLPutCalendarJobRequest struct {
+	CalendarID string
+	JobID      string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutCalendarJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("calendars") + 1 + len(r.CalendarID) + 1 + len("jobs") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("calendars")
+	path.WriteString("/")
+	path.WriteString(r.CalendarID)
+	path.WriteString("/")
+	path.WriteString("jobs")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutCalendarJob) WithContext(v context.Context) func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutCalendarJob) WithPretty() func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutCalendarJob) WithHuman() func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutCalendarJob) WithErrorTrace() func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutCalendarJob) WithFilterPath(v ...string) func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutCalendarJob) WithHeader(h map[string]string) func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutCalendarJob) WithOpaqueID(s string) func(*MLPutCalendarJobRequest) {
+	return func(r *MLPutCalendarJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_data_frame_analytics.go b/esapi/api.xpack.ml.put_data_frame_analytics.go
new file mode 100644
index 0000000000..d8255ddd45
--- /dev/null
+++ b/esapi/api.xpack.ml.put_data_frame_analytics.go
@@ -0,0 +1,212 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPutDataFrameAnalyticsFunc(t Transport) MLPutDataFrameAnalytics {
+	return func(id string, body io.Reader, o ...func(*MLPutDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLPutDataFrameAnalyticsRequest{ID: id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutDataFrameAnalytics - Instantiates a data frame analytics job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-dfanalytics.html.
+//
+type MLPutDataFrameAnalytics func(id string, body io.Reader, o ...func(*MLPutDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLPutDataFrameAnalyticsRequest configures the ML Put Data Frame Analytics API request.
+//
+type MLPutDataFrameAnalyticsRequest struct {
+	ID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	path.WriteString("/")
+	path.WriteString(r.ID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutDataFrameAnalytics) WithContext(v context.Context) func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutDataFrameAnalytics) WithPretty() func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutDataFrameAnalytics) WithHuman() func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutDataFrameAnalytics) WithErrorTrace() func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutDataFrameAnalytics) WithFilterPath(v ...string) func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutDataFrameAnalytics) WithHeader(h map[string]string) func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutDataFrameAnalytics) WithOpaqueID(s string) func(*MLPutDataFrameAnalyticsRequest) {
+	return func(r *MLPutDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_datafeed.go b/esapi/api.xpack.ml.put_datafeed.go
new file mode 100644
index 0000000000..f3312d1173
--- /dev/null
+++ b/esapi/api.xpack.ml.put_datafeed.go
@@ -0,0 +1,264 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLPutDatafeedFunc(t Transport) MLPutDatafeed {
+	return func(body io.Reader, datafeed_id string, o ...func(*MLPutDatafeedRequest)) (*Response, error) {
+		var r = MLPutDatafeedRequest{Body: body, DatafeedID: datafeed_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutDatafeed - Instantiates a datafeed.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-datafeed.html.
+//
+type MLPutDatafeed func(body io.Reader, datafeed_id string, o ...func(*MLPutDatafeedRequest)) (*Response, error)
+
+// MLPutDatafeedRequest configures the ML Put Datafeed API request.
+//
+type MLPutDatafeedRequest struct {
+	Body io.Reader
+
+	DatafeedID string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreThrottled   *bool
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	path.WriteString("/")
+	path.WriteString(r.DatafeedID)
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreThrottled != nil {
+		params["ignore_throttled"] = strconv.FormatBool(*r.IgnoreThrottled)
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutDatafeed) WithContext(v context.Context) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - ignore if the source indices expressions resolves to no concrete indices (default: true).
+//
+func (f MLPutDatafeed) WithAllowNoIndices(v bool) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether source index expressions should get expanded to open or closed indices (default: open).
+//
+func (f MLPutDatafeed) WithExpandWildcards(v string) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreThrottled - ignore indices that are marked as throttled (default: true).
+//
+func (f MLPutDatafeed) WithIgnoreThrottled(v bool) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.IgnoreThrottled = &v
+	}
+}
+
+// WithIgnoreUnavailable - ignore unavailable indexes (default: false).
+//
+func (f MLPutDatafeed) WithIgnoreUnavailable(v bool) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutDatafeed) WithPretty() func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutDatafeed) WithHuman() func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutDatafeed) WithErrorTrace() func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutDatafeed) WithFilterPath(v ...string) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutDatafeed) WithHeader(h map[string]string) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutDatafeed) WithOpaqueID(s string) func(*MLPutDatafeedRequest) {
+	return func(r *MLPutDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_filter.go b/esapi/api.xpack.ml.put_filter.go
new file mode 100644
index 0000000000..e543036fe1
--- /dev/null
+++ b/esapi/api.xpack.ml.put_filter.go
@@ -0,0 +1,210 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLPutFilterFunc(t Transport) MLPutFilter {
+	return func(body io.Reader, filter_id string, o ...func(*MLPutFilterRequest)) (*Response, error) {
+		var r = MLPutFilterRequest{Body: body, FilterID: filter_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutFilter - Instantiates a filter.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-filter.html.
+//
+type MLPutFilter func(body io.Reader, filter_id string, o ...func(*MLPutFilterRequest)) (*Response, error)
+
+// MLPutFilterRequest configures the ML Put Filter API request.
+//
+type MLPutFilterRequest struct {
+	Body io.Reader
+
+	FilterID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutFilterRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("filters") + 1 + len(r.FilterID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("filters")
+	path.WriteString("/")
+	path.WriteString(r.FilterID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutFilter) WithContext(v context.Context) func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutFilter) WithPretty() func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutFilter) WithHuman() func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutFilter) WithErrorTrace() func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutFilter) WithFilterPath(v ...string) func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutFilter) WithHeader(h map[string]string) func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutFilter) WithOpaqueID(s string) func(*MLPutFilterRequest) {
+	return func(r *MLPutFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_job.go b/esapi/api.xpack.ml.put_job.go
new file mode 100644
index 0000000000..2c6765ec6d
--- /dev/null
+++ b/esapi/api.xpack.ml.put_job.go
@@ -0,0 +1,264 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLPutJobFunc(t Transport) MLPutJob {
+	return func(job_id string, body io.Reader, o ...func(*MLPutJobRequest)) (*Response, error) {
+		var r = MLPutJobRequest{JobID: job_id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutJob - Instantiates an anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-job.html.
+//
+type MLPutJob func(job_id string, body io.Reader, o ...func(*MLPutJobRequest)) (*Response, error)
+
+// MLPutJobRequest configures the ML Put Job API request.
+//
+type MLPutJobRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreThrottled   *bool
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreThrottled != nil {
+		params["ignore_throttled"] = strconv.FormatBool(*r.IgnoreThrottled)
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutJob) WithContext(v context.Context) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - ignore if the source indices expressions resolves to no concrete indices (default: true). only set if datafeed_config is provided..
+//
+func (f MLPutJob) WithAllowNoIndices(v bool) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether source index expressions should get expanded to open or closed indices (default: open). only set if datafeed_config is provided..
+//
+func (f MLPutJob) WithExpandWildcards(v string) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreThrottled - ignore indices that are marked as throttled (default: true). only set if datafeed_config is provided..
+//
+func (f MLPutJob) WithIgnoreThrottled(v bool) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.IgnoreThrottled = &v
+	}
+}
+
+// WithIgnoreUnavailable - ignore unavailable indexes (default: false). only set if datafeed_config is provided..
+//
+func (f MLPutJob) WithIgnoreUnavailable(v bool) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutJob) WithPretty() func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutJob) WithHuman() func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutJob) WithErrorTrace() func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutJob) WithFilterPath(v ...string) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutJob) WithHeader(h map[string]string) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutJob) WithOpaqueID(s string) func(*MLPutJobRequest) {
+	return func(r *MLPutJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_trained_model.go b/esapi/api.xpack.ml.put_trained_model.go
new file mode 100644
index 0000000000..4dad30f420
--- /dev/null
+++ b/esapi/api.xpack.ml.put_trained_model.go
@@ -0,0 +1,225 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLPutTrainedModelFunc(t Transport) MLPutTrainedModel {
+	return func(body io.Reader, model_id string, o ...func(*MLPutTrainedModelRequest)) (*Response, error) {
+		var r = MLPutTrainedModelRequest{Body: body, ModelID: model_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutTrainedModel - Creates an inference trained model.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-trained-models.html.
+//
+type MLPutTrainedModel func(body io.Reader, model_id string, o ...func(*MLPutTrainedModelRequest)) (*Response, error)
+
+// MLPutTrainedModelRequest configures the ML Put Trained Model API request.
+//
+type MLPutTrainedModelRequest struct {
+	Body io.Reader
+
+	ModelID string
+
+	DeferDefinitionDecompression *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutTrainedModelRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	path.WriteString("/")
+	path.WriteString(r.ModelID)
+
+	params = make(map[string]string)
+
+	if r.DeferDefinitionDecompression != nil {
+		params["defer_definition_decompression"] = strconv.FormatBool(*r.DeferDefinitionDecompression)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutTrainedModel) WithContext(v context.Context) func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDeferDefinitionDecompression - if set to `true` and a `compressed_definition` is provided, the request defers definition decompression and skips relevant validations..
+//
+func (f MLPutTrainedModel) WithDeferDefinitionDecompression(v bool) func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.DeferDefinitionDecompression = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutTrainedModel) WithPretty() func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutTrainedModel) WithHuman() func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutTrainedModel) WithErrorTrace() func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutTrainedModel) WithFilterPath(v ...string) func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutTrainedModel) WithHeader(h map[string]string) func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutTrainedModel) WithOpaqueID(s string) func(*MLPutTrainedModelRequest) {
+	return func(r *MLPutTrainedModelRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.put_trained_model_alias.go b/esapi/api.xpack.ml.put_trained_model_alias.go
new file mode 100644
index 0000000000..94773c316e
--- /dev/null
+++ b/esapi/api.xpack.ml.put_trained_model_alias.go
@@ -0,0 +1,223 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLPutTrainedModelAliasFunc(t Transport) MLPutTrainedModelAlias {
+	return func(model_alias string, model_id string, o ...func(*MLPutTrainedModelAliasRequest)) (*Response, error) {
+		var r = MLPutTrainedModelAliasRequest{ModelAlias: model_alias, ModelID: model_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLPutTrainedModelAlias - Creates a new model alias (or reassigns an existing one) to refer to the trained model
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-trained-models-aliases.html.
+//
+type MLPutTrainedModelAlias func(model_id string, model_alias string, o ...func(*MLPutTrainedModelAliasRequest)) (*Response, error)
+
+// MLPutTrainedModelAliasRequest configures the ML Put Trained Model Alias API request.
+//
+type MLPutTrainedModelAliasRequest struct {
+	ModelAlias string
+	ModelID    string
+
+	Reassign *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLPutTrainedModelAliasRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_ml") + 1 + len("trained_models") + 1 + len(r.ModelID) + 1 + len("model_aliases") + 1 + len(r.ModelAlias))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("trained_models")
+	path.WriteString("/")
+	path.WriteString(r.ModelID)
+	path.WriteString("/")
+	path.WriteString("model_aliases")
+	path.WriteString("/")
+	path.WriteString(r.ModelAlias)
+
+	params = make(map[string]string)
+
+	if r.Reassign != nil {
+		params["reassign"] = strconv.FormatBool(*r.Reassign)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLPutTrainedModelAlias) WithContext(v context.Context) func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.ctx = v
+	}
+}
+
+// WithReassign - if the model_alias already exists and points to a separate model_id, this parameter must be true. defaults to false..
+//
+func (f MLPutTrainedModelAlias) WithReassign(v bool) func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.Reassign = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLPutTrainedModelAlias) WithPretty() func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLPutTrainedModelAlias) WithHuman() func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLPutTrainedModelAlias) WithErrorTrace() func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLPutTrainedModelAlias) WithFilterPath(v ...string) func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLPutTrainedModelAlias) WithHeader(h map[string]string) func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLPutTrainedModelAlias) WithOpaqueID(s string) func(*MLPutTrainedModelAliasRequest) {
+	return func(r *MLPutTrainedModelAliasRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.reset_job.go b/esapi/api.xpack.ml.reset_job.go
new file mode 100644
index 0000000000..9f8376bf86
--- /dev/null
+++ b/esapi/api.xpack.ml.reset_job.go
@@ -0,0 +1,220 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLResetJobFunc(t Transport) MLResetJob {
+	return func(job_id string, o ...func(*MLResetJobRequest)) (*Response, error) {
+		var r = MLResetJobRequest{JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLResetJob - Resets an existing anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-reset-job.html.
+//
+type MLResetJob func(job_id string, o ...func(*MLResetJobRequest)) (*Response, error)
+
+// MLResetJobRequest configures the ML Reset Job API request.
+//
+type MLResetJobRequest struct {
+	JobID string
+
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLResetJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_reset"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_reset")
+
+	params = make(map[string]string)
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLResetJob) WithContext(v context.Context) func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithWaitForCompletion - should this request wait until the operation has completed before returning.
+//
+func (f MLResetJob) WithWaitForCompletion(v bool) func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLResetJob) WithPretty() func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLResetJob) WithHuman() func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLResetJob) WithErrorTrace() func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLResetJob) WithFilterPath(v ...string) func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLResetJob) WithHeader(h map[string]string) func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLResetJob) WithOpaqueID(s string) func(*MLResetJobRequest) {
+	return func(r *MLResetJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.revert_model_snapshot.go b/esapi/api.xpack.ml.revert_model_snapshot.go
new file mode 100644
index 0000000000..0a946be2b2
--- /dev/null
+++ b/esapi/api.xpack.ml.revert_model_snapshot.go
@@ -0,0 +1,240 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLRevertModelSnapshotFunc(t Transport) MLRevertModelSnapshot {
+	return func(snapshot_id string, job_id string, o ...func(*MLRevertModelSnapshotRequest)) (*Response, error) {
+		var r = MLRevertModelSnapshotRequest{SnapshotID: snapshot_id, JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLRevertModelSnapshot - Reverts to a specific snapshot.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-revert-snapshot.html.
+//
+type MLRevertModelSnapshot func(snapshot_id string, job_id string, o ...func(*MLRevertModelSnapshotRequest)) (*Response, error)
+
+// MLRevertModelSnapshotRequest configures the ML Revert Model Snapshot API request.
+//
+type MLRevertModelSnapshotRequest struct {
+	Body io.Reader
+
+	JobID      string
+	SnapshotID string
+
+	DeleteInterveningResults *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLRevertModelSnapshotRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("model_snapshots") + 1 + len(r.SnapshotID) + 1 + len("_revert"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("model_snapshots")
+	path.WriteString("/")
+	path.WriteString(r.SnapshotID)
+	path.WriteString("/")
+	path.WriteString("_revert")
+
+	params = make(map[string]string)
+
+	if r.DeleteInterveningResults != nil {
+		params["delete_intervening_results"] = strconv.FormatBool(*r.DeleteInterveningResults)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLRevertModelSnapshot) WithContext(v context.Context) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Reversion options.
+//
+func (f MLRevertModelSnapshot) WithBody(v io.Reader) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.Body = v
+	}
+}
+
+// WithDeleteInterveningResults - should we reset the results back to the time of the snapshot?.
+//
+func (f MLRevertModelSnapshot) WithDeleteInterveningResults(v bool) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.DeleteInterveningResults = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLRevertModelSnapshot) WithPretty() func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLRevertModelSnapshot) WithHuman() func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLRevertModelSnapshot) WithErrorTrace() func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLRevertModelSnapshot) WithFilterPath(v ...string) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLRevertModelSnapshot) WithHeader(h map[string]string) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLRevertModelSnapshot) WithOpaqueID(s string) func(*MLRevertModelSnapshotRequest) {
+	return func(r *MLRevertModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.set_upgrade_mode.go b/esapi/api.xpack.ml.set_upgrade_mode.go
new file mode 100644
index 0000000000..09f02c48f3
--- /dev/null
+++ b/esapi/api.xpack.ml.set_upgrade_mode.go
@@ -0,0 +1,225 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLSetUpgradeModeFunc(t Transport) MLSetUpgradeMode {
+	return func(o ...func(*MLSetUpgradeModeRequest)) (*Response, error) {
+		var r = MLSetUpgradeModeRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLSetUpgradeMode - Sets a cluster wide upgrade_mode setting that prepares machine learning indices for an upgrade.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-set-upgrade-mode.html.
+//
+type MLSetUpgradeMode func(o ...func(*MLSetUpgradeModeRequest)) (*Response, error)
+
+// MLSetUpgradeModeRequest configures the ML Set Upgrade Mode API request.
+//
+type MLSetUpgradeModeRequest struct {
+	Enabled *bool
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLSetUpgradeModeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/set_upgrade_mode"))
+	path.WriteString("/_ml/set_upgrade_mode")
+
+	params = make(map[string]string)
+
+	if r.Enabled != nil {
+		params["enabled"] = strconv.FormatBool(*r.Enabled)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLSetUpgradeMode) WithContext(v context.Context) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithEnabled - whether to enable upgrade_mode ml setting or not. defaults to false..
+//
+func (f MLSetUpgradeMode) WithEnabled(v bool) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.Enabled = &v
+	}
+}
+
+// WithTimeout - controls the time to wait before action times out. defaults to 30 seconds.
+//
+func (f MLSetUpgradeMode) WithTimeout(v time.Duration) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLSetUpgradeMode) WithPretty() func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLSetUpgradeMode) WithHuman() func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLSetUpgradeMode) WithErrorTrace() func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLSetUpgradeMode) WithFilterPath(v ...string) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLSetUpgradeMode) WithHeader(h map[string]string) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLSetUpgradeMode) WithOpaqueID(s string) func(*MLSetUpgradeModeRequest) {
+	return func(r *MLSetUpgradeModeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.start_data_frame_analytics.go b/esapi/api.xpack.ml.start_data_frame_analytics.go
new file mode 100644
index 0000000000..6b5e8e3485
--- /dev/null
+++ b/esapi/api.xpack.ml.start_data_frame_analytics.go
@@ -0,0 +1,237 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newMLStartDataFrameAnalyticsFunc(t Transport) MLStartDataFrameAnalytics {
+	return func(id string, o ...func(*MLStartDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLStartDataFrameAnalyticsRequest{ID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLStartDataFrameAnalytics - Starts a data frame analytics job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/start-dfanalytics.html.
+//
+type MLStartDataFrameAnalytics func(id string, o ...func(*MLStartDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLStartDataFrameAnalyticsRequest configures the ML Start Data Frame Analytics API request.
+//
+type MLStartDataFrameAnalyticsRequest struct {
+	ID string
+
+	Body io.Reader
+
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLStartDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID) + 1 + len("_start"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	path.WriteString("/")
+	path.WriteString(r.ID)
+	path.WriteString("/")
+	path.WriteString("_start")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLStartDataFrameAnalytics) WithContext(v context.Context) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The start data frame analytics parameters.
+//
+func (f MLStartDataFrameAnalytics) WithBody(v io.Reader) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.Body = v
+	}
+}
+
+// WithTimeout - controls the time to wait until the task has started. defaults to 20 seconds.
+//
+func (f MLStartDataFrameAnalytics) WithTimeout(v time.Duration) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLStartDataFrameAnalytics) WithPretty() func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLStartDataFrameAnalytics) WithHuman() func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLStartDataFrameAnalytics) WithErrorTrace() func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLStartDataFrameAnalytics) WithFilterPath(v ...string) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLStartDataFrameAnalytics) WithHeader(h map[string]string) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLStartDataFrameAnalytics) WithOpaqueID(s string) func(*MLStartDataFrameAnalyticsRequest) {
+	return func(r *MLStartDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.start_datafeed.go b/esapi/api.xpack.ml.start_datafeed.go
new file mode 100644
index 0000000000..1a61040945
--- /dev/null
+++ b/esapi/api.xpack.ml.start_datafeed.go
@@ -0,0 +1,261 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newMLStartDatafeedFunc(t Transport) MLStartDatafeed {
+	return func(datafeed_id string, o ...func(*MLStartDatafeedRequest)) (*Response, error) {
+		var r = MLStartDatafeedRequest{DatafeedID: datafeed_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLStartDatafeed - Starts one or more datafeeds.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-start-datafeed.html.
+//
+type MLStartDatafeed func(datafeed_id string, o ...func(*MLStartDatafeedRequest)) (*Response, error)
+
+// MLStartDatafeedRequest configures the ML Start Datafeed API request.
+//
+type MLStartDatafeedRequest struct {
+	Body io.Reader
+
+	DatafeedID string
+
+	End     string
+	Start   string
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLStartDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID) + 1 + len("_start"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	path.WriteString("/")
+	path.WriteString(r.DatafeedID)
+	path.WriteString("/")
+	path.WriteString("_start")
+
+	params = make(map[string]string)
+
+	if r.End != "" {
+		params["end"] = r.End
+	}
+
+	if r.Start != "" {
+		params["start"] = r.Start
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLStartDatafeed) WithContext(v context.Context) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The start datafeed parameters.
+//
+func (f MLStartDatafeed) WithBody(v io.Reader) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.Body = v
+	}
+}
+
+// WithEnd - the end time when the datafeed should stop. when not set, the datafeed continues in real time.
+//
+func (f MLStartDatafeed) WithEnd(v string) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.End = v
+	}
+}
+
+// WithStart - the start time from where the datafeed should begin.
+//
+func (f MLStartDatafeed) WithStart(v string) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.Start = v
+	}
+}
+
+// WithTimeout - controls the time to wait until a datafeed has started. default to 20 seconds.
+//
+func (f MLStartDatafeed) WithTimeout(v time.Duration) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLStartDatafeed) WithPretty() func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLStartDatafeed) WithHuman() func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLStartDatafeed) WithErrorTrace() func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLStartDatafeed) WithFilterPath(v ...string) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLStartDatafeed) WithHeader(h map[string]string) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLStartDatafeed) WithOpaqueID(s string) func(*MLStartDatafeedRequest) {
+	return func(r *MLStartDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.stop_data_frame_analytics.go b/esapi/api.xpack.ml.stop_data_frame_analytics.go
new file mode 100644
index 0000000000..f14d9c386f
--- /dev/null
+++ b/esapi/api.xpack.ml.stop_data_frame_analytics.go
@@ -0,0 +1,264 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLStopDataFrameAnalyticsFunc(t Transport) MLStopDataFrameAnalytics {
+	return func(id string, o ...func(*MLStopDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLStopDataFrameAnalyticsRequest{ID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLStopDataFrameAnalytics - Stops one or more data frame analytics jobs.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/stop-dfanalytics.html.
+//
+type MLStopDataFrameAnalytics func(id string, o ...func(*MLStopDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLStopDataFrameAnalyticsRequest configures the ML Stop Data Frame Analytics API request.
+//
+type MLStopDataFrameAnalyticsRequest struct {
+	ID string
+
+	Body io.Reader
+
+	AllowNoMatch *bool
+	Force        *bool
+	Timeout      time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLStopDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.ID) + 1 + len("_stop"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	path.WriteString("/")
+	path.WriteString(r.ID)
+	path.WriteString("/")
+	path.WriteString("_stop")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLStopDataFrameAnalytics) WithContext(v context.Context) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The stop data frame analytics parameters.
+//
+func (f MLStopDataFrameAnalytics) WithBody(v io.Reader) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.Body = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no data frame analytics. (this includes `_all` string or when no data frame analytics have been specified).
+//
+func (f MLStopDataFrameAnalytics) WithAllowNoMatch(v bool) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithForce - true if the data frame analytics should be forcefully stopped.
+//
+func (f MLStopDataFrameAnalytics) WithForce(v bool) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until the task has stopped. defaults to 20 seconds.
+//
+func (f MLStopDataFrameAnalytics) WithTimeout(v time.Duration) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLStopDataFrameAnalytics) WithPretty() func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLStopDataFrameAnalytics) WithHuman() func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLStopDataFrameAnalytics) WithErrorTrace() func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLStopDataFrameAnalytics) WithFilterPath(v ...string) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLStopDataFrameAnalytics) WithHeader(h map[string]string) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLStopDataFrameAnalytics) WithOpaqueID(s string) func(*MLStopDataFrameAnalyticsRequest) {
+	return func(r *MLStopDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.stop_datafeed.go b/esapi/api.xpack.ml.stop_datafeed.go
new file mode 100644
index 0000000000..825a1d57c1
--- /dev/null
+++ b/esapi/api.xpack.ml.stop_datafeed.go
@@ -0,0 +1,275 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLStopDatafeedFunc(t Transport) MLStopDatafeed {
+	return func(datafeed_id string, o ...func(*MLStopDatafeedRequest)) (*Response, error) {
+		var r = MLStopDatafeedRequest{DatafeedID: datafeed_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLStopDatafeed - Stops one or more datafeeds.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-stop-datafeed.html.
+//
+type MLStopDatafeed func(datafeed_id string, o ...func(*MLStopDatafeedRequest)) (*Response, error)
+
+// MLStopDatafeedRequest configures the ML Stop Datafeed API request.
+//
+type MLStopDatafeedRequest struct {
+	Body io.Reader
+
+	DatafeedID string
+
+	AllowNoDatafeeds *bool
+	AllowNoMatch     *bool
+	Force            *bool
+	Timeout          time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLStopDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID) + 1 + len("_stop"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	path.WriteString("/")
+	path.WriteString(r.DatafeedID)
+	path.WriteString("/")
+	path.WriteString("_stop")
+
+	params = make(map[string]string)
+
+	if r.AllowNoDatafeeds != nil {
+		params["allow_no_datafeeds"] = strconv.FormatBool(*r.AllowNoDatafeeds)
+	}
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLStopDatafeed) WithContext(v context.Context) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The URL params optionally sent in the body.
+//
+func (f MLStopDatafeed) WithBody(v io.Reader) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.Body = v
+	}
+}
+
+// WithAllowNoDatafeeds - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLStopDatafeed) WithAllowNoDatafeeds(v bool) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.AllowNoDatafeeds = &v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no datafeeds. (this includes `_all` string or when no datafeeds have been specified).
+//
+func (f MLStopDatafeed) WithAllowNoMatch(v bool) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithForce - true if the datafeed should be forcefully stopped..
+//
+func (f MLStopDatafeed) WithForce(v bool) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until a datafeed has stopped. default to 20 seconds.
+//
+func (f MLStopDatafeed) WithTimeout(v time.Duration) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLStopDatafeed) WithPretty() func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLStopDatafeed) WithHuman() func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLStopDatafeed) WithErrorTrace() func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLStopDatafeed) WithFilterPath(v ...string) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLStopDatafeed) WithHeader(h map[string]string) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLStopDatafeed) WithOpaqueID(s string) func(*MLStopDatafeedRequest) {
+	return func(r *MLStopDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.update_data_frame_analytics.go b/esapi/api.xpack.ml.update_data_frame_analytics.go
new file mode 100644
index 0000000000..4817070ba7
--- /dev/null
+++ b/esapi/api.xpack.ml.update_data_frame_analytics.go
@@ -0,0 +1,214 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLUpdateDataFrameAnalyticsFunc(t Transport) MLUpdateDataFrameAnalytics {
+	return func(id string, body io.Reader, o ...func(*MLUpdateDataFrameAnalyticsRequest)) (*Response, error) {
+		var r = MLUpdateDataFrameAnalyticsRequest{DocumentID: id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpdateDataFrameAnalytics - Updates certain properties of a data frame analytics job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/update-dfanalytics.html.
+//
+type MLUpdateDataFrameAnalytics func(id string, body io.Reader, o ...func(*MLUpdateDataFrameAnalyticsRequest)) (*Response, error)
+
+// MLUpdateDataFrameAnalyticsRequest configures the ML Update Data Frame Analytics API request.
+//
+type MLUpdateDataFrameAnalyticsRequest struct {
+	DocumentID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpdateDataFrameAnalyticsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("data_frame") + 1 + len("analytics") + 1 + len(r.DocumentID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("data_frame")
+	path.WriteString("/")
+	path.WriteString("analytics")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpdateDataFrameAnalytics) WithContext(v context.Context) func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpdateDataFrameAnalytics) WithPretty() func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpdateDataFrameAnalytics) WithHuman() func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpdateDataFrameAnalytics) WithErrorTrace() func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpdateDataFrameAnalytics) WithFilterPath(v ...string) func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpdateDataFrameAnalytics) WithHeader(h map[string]string) func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpdateDataFrameAnalytics) WithOpaqueID(s string) func(*MLUpdateDataFrameAnalyticsRequest) {
+	return func(r *MLUpdateDataFrameAnalyticsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.update_datafeed.go b/esapi/api.xpack.ml.update_datafeed.go
new file mode 100644
index 0000000000..b2a30c2ee3
--- /dev/null
+++ b/esapi/api.xpack.ml.update_datafeed.go
@@ -0,0 +1,266 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newMLUpdateDatafeedFunc(t Transport) MLUpdateDatafeed {
+	return func(body io.Reader, datafeed_id string, o ...func(*MLUpdateDatafeedRequest)) (*Response, error) {
+		var r = MLUpdateDatafeedRequest{Body: body, DatafeedID: datafeed_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpdateDatafeed - Updates certain properties of a datafeed.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-datafeed.html.
+//
+type MLUpdateDatafeed func(body io.Reader, datafeed_id string, o ...func(*MLUpdateDatafeedRequest)) (*Response, error)
+
+// MLUpdateDatafeedRequest configures the ML Update Datafeed API request.
+//
+type MLUpdateDatafeedRequest struct {
+	Body io.Reader
+
+	DatafeedID string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreThrottled   *bool
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpdateDatafeedRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("datafeeds") + 1 + len(r.DatafeedID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("datafeeds")
+	path.WriteString("/")
+	path.WriteString(r.DatafeedID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreThrottled != nil {
+		params["ignore_throttled"] = strconv.FormatBool(*r.IgnoreThrottled)
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpdateDatafeed) WithContext(v context.Context) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoIndices - ignore if the source indices expressions resolves to no concrete indices (default: true).
+//
+func (f MLUpdateDatafeed) WithAllowNoIndices(v bool) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether source index expressions should get expanded to open or closed indices (default: open).
+//
+func (f MLUpdateDatafeed) WithExpandWildcards(v string) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreThrottled - ignore indices that are marked as throttled (default: true).
+//
+func (f MLUpdateDatafeed) WithIgnoreThrottled(v bool) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.IgnoreThrottled = &v
+	}
+}
+
+// WithIgnoreUnavailable - ignore unavailable indexes (default: false).
+//
+func (f MLUpdateDatafeed) WithIgnoreUnavailable(v bool) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpdateDatafeed) WithPretty() func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpdateDatafeed) WithHuman() func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpdateDatafeed) WithErrorTrace() func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpdateDatafeed) WithFilterPath(v ...string) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpdateDatafeed) WithHeader(h map[string]string) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpdateDatafeed) WithOpaqueID(s string) func(*MLUpdateDatafeedRequest) {
+	return func(r *MLUpdateDatafeedRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.update_filter.go b/esapi/api.xpack.ml.update_filter.go
new file mode 100644
index 0000000000..6f1ef81e79
--- /dev/null
+++ b/esapi/api.xpack.ml.update_filter.go
@@ -0,0 +1,212 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLUpdateFilterFunc(t Transport) MLUpdateFilter {
+	return func(body io.Reader, filter_id string, o ...func(*MLUpdateFilterRequest)) (*Response, error) {
+		var r = MLUpdateFilterRequest{Body: body, FilterID: filter_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpdateFilter - Updates the description of a filter, adds items, or removes items.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-filter.html.
+//
+type MLUpdateFilter func(body io.Reader, filter_id string, o ...func(*MLUpdateFilterRequest)) (*Response, error)
+
+// MLUpdateFilterRequest configures the ML Update Filter API request.
+//
+type MLUpdateFilterRequest struct {
+	Body io.Reader
+
+	FilterID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpdateFilterRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("filters") + 1 + len(r.FilterID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("filters")
+	path.WriteString("/")
+	path.WriteString(r.FilterID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpdateFilter) WithContext(v context.Context) func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpdateFilter) WithPretty() func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpdateFilter) WithHuman() func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpdateFilter) WithErrorTrace() func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpdateFilter) WithFilterPath(v ...string) func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpdateFilter) WithHeader(h map[string]string) func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpdateFilter) WithOpaqueID(s string) func(*MLUpdateFilterRequest) {
+	return func(r *MLUpdateFilterRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.update_job.go b/esapi/api.xpack.ml.update_job.go
new file mode 100644
index 0000000000..b7c971fcdb
--- /dev/null
+++ b/esapi/api.xpack.ml.update_job.go
@@ -0,0 +1,212 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLUpdateJobFunc(t Transport) MLUpdateJob {
+	return func(job_id string, body io.Reader, o ...func(*MLUpdateJobRequest)) (*Response, error) {
+		var r = MLUpdateJobRequest{JobID: job_id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpdateJob - Updates certain properties of an anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-job.html.
+//
+type MLUpdateJob func(job_id string, body io.Reader, o ...func(*MLUpdateJobRequest)) (*Response, error)
+
+// MLUpdateJobRequest configures the ML Update Job API request.
+//
+type MLUpdateJobRequest struct {
+	Body io.Reader
+
+	JobID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpdateJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpdateJob) WithContext(v context.Context) func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpdateJob) WithPretty() func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpdateJob) WithHuman() func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpdateJob) WithErrorTrace() func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpdateJob) WithFilterPath(v ...string) func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpdateJob) WithHeader(h map[string]string) func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpdateJob) WithOpaqueID(s string) func(*MLUpdateJobRequest) {
+	return func(r *MLUpdateJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.update_model_snapshot.go b/esapi/api.xpack.ml.update_model_snapshot.go
new file mode 100644
index 0000000000..c8f57ab361
--- /dev/null
+++ b/esapi/api.xpack.ml.update_model_snapshot.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLUpdateModelSnapshotFunc(t Transport) MLUpdateModelSnapshot {
+	return func(snapshot_id string, job_id string, body io.Reader, o ...func(*MLUpdateModelSnapshotRequest)) (*Response, error) {
+		var r = MLUpdateModelSnapshotRequest{SnapshotID: snapshot_id, JobID: job_id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpdateModelSnapshot - Updates certain properties of a snapshot.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-snapshot.html.
+//
+type MLUpdateModelSnapshot func(snapshot_id string, job_id string, body io.Reader, o ...func(*MLUpdateModelSnapshotRequest)) (*Response, error)
+
+// MLUpdateModelSnapshotRequest configures the ML Update Model Snapshot API request.
+//
+type MLUpdateModelSnapshotRequest struct {
+	Body io.Reader
+
+	JobID      string
+	SnapshotID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpdateModelSnapshotRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("model_snapshots") + 1 + len(r.SnapshotID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("model_snapshots")
+	path.WriteString("/")
+	path.WriteString(r.SnapshotID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpdateModelSnapshot) WithContext(v context.Context) func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpdateModelSnapshot) WithPretty() func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpdateModelSnapshot) WithHuman() func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpdateModelSnapshot) WithErrorTrace() func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpdateModelSnapshot) WithFilterPath(v ...string) func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpdateModelSnapshot) WithHeader(h map[string]string) func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpdateModelSnapshot) WithOpaqueID(s string) func(*MLUpdateModelSnapshotRequest) {
+	return func(r *MLUpdateModelSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.upgrade_job_snapshot.go b/esapi/api.xpack.ml.upgrade_job_snapshot.go
new file mode 100644
index 0000000000..9e8e125ef7
--- /dev/null
+++ b/esapi/api.xpack.ml.upgrade_job_snapshot.go
@@ -0,0 +1,239 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newMLUpgradeJobSnapshotFunc(t Transport) MLUpgradeJobSnapshot {
+	return func(snapshot_id string, job_id string, o ...func(*MLUpgradeJobSnapshotRequest)) (*Response, error) {
+		var r = MLUpgradeJobSnapshotRequest{SnapshotID: snapshot_id, JobID: job_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLUpgradeJobSnapshot - Upgrades a given job snapshot to the current major version.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-upgrade-job-model-snapshot.html.
+//
+type MLUpgradeJobSnapshot func(snapshot_id string, job_id string, o ...func(*MLUpgradeJobSnapshotRequest)) (*Response, error)
+
+// MLUpgradeJobSnapshotRequest configures the ML Upgrade Job Snapshot API request.
+//
+type MLUpgradeJobSnapshotRequest struct {
+	JobID      string
+	SnapshotID string
+
+	Timeout           time.Duration
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLUpgradeJobSnapshotRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_ml") + 1 + len("anomaly_detectors") + 1 + len(r.JobID) + 1 + len("model_snapshots") + 1 + len(r.SnapshotID) + 1 + len("_upgrade"))
+	path.WriteString("/")
+	path.WriteString("_ml")
+	path.WriteString("/")
+	path.WriteString("anomaly_detectors")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("model_snapshots")
+	path.WriteString("/")
+	path.WriteString(r.SnapshotID)
+	path.WriteString("/")
+	path.WriteString("_upgrade")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLUpgradeJobSnapshot) WithContext(v context.Context) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTimeout - how long should the api wait for the job to be opened and the old snapshot to be loaded..
+//
+func (f MLUpgradeJobSnapshot) WithTimeout(v time.Duration) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForCompletion - should the request wait until the task is complete before responding to the caller. default is false..
+//
+func (f MLUpgradeJobSnapshot) WithWaitForCompletion(v bool) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLUpgradeJobSnapshot) WithPretty() func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLUpgradeJobSnapshot) WithHuman() func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLUpgradeJobSnapshot) WithErrorTrace() func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLUpgradeJobSnapshot) WithFilterPath(v ...string) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLUpgradeJobSnapshot) WithHeader(h map[string]string) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLUpgradeJobSnapshot) WithOpaqueID(s string) func(*MLUpgradeJobSnapshotRequest) {
+	return func(r *MLUpgradeJobSnapshotRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.validate.go b/esapi/api.xpack.ml.validate.go
new file mode 100644
index 0000000000..c89963f2aa
--- /dev/null
+++ b/esapi/api.xpack.ml.validate.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLValidateFunc(t Transport) MLValidate {
+	return func(body io.Reader, o ...func(*MLValidateRequest)) (*Response, error) {
+		var r = MLValidateRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLValidate - Validates an anomaly detection job.
+//
+// See full documentation at https://www.elastic.co/guide/en/machine-learning/current/ml-jobs.html.
+//
+type MLValidate func(body io.Reader, o ...func(*MLValidateRequest)) (*Response, error)
+
+// MLValidateRequest configures the ML Validate API request.
+//
+type MLValidateRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLValidateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/anomaly_detectors/_validate"))
+	path.WriteString("/_ml/anomaly_detectors/_validate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLValidate) WithContext(v context.Context) func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLValidate) WithPretty() func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLValidate) WithHuman() func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLValidate) WithErrorTrace() func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLValidate) WithFilterPath(v ...string) func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLValidate) WithHeader(h map[string]string) func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLValidate) WithOpaqueID(s string) func(*MLValidateRequest) {
+	return func(r *MLValidateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ml.validate_detector.go b/esapi/api.xpack.ml.validate_detector.go
new file mode 100644
index 0000000000..a1816d33ed
--- /dev/null
+++ b/esapi/api.xpack.ml.validate_detector.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMLValidateDetectorFunc(t Transport) MLValidateDetector {
+	return func(body io.Reader, o ...func(*MLValidateDetectorRequest)) (*Response, error) {
+		var r = MLValidateDetectorRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MLValidateDetector - Validates an anomaly detection detector.
+//
+// See full documentation at https://www.elastic.co/guide/en/machine-learning/current/ml-jobs.html.
+//
+type MLValidateDetector func(body io.Reader, o ...func(*MLValidateDetectorRequest)) (*Response, error)
+
+// MLValidateDetectorRequest configures the ML Validate Detector API request.
+//
+type MLValidateDetectorRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MLValidateDetectorRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_ml/anomaly_detectors/_validate/detector"))
+	path.WriteString("/_ml/anomaly_detectors/_validate/detector")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MLValidateDetector) WithContext(v context.Context) func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MLValidateDetector) WithPretty() func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MLValidateDetector) WithHuman() func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MLValidateDetector) WithErrorTrace() func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MLValidateDetector) WithFilterPath(v ...string) func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MLValidateDetector) WithHeader(h map[string]string) func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MLValidateDetector) WithOpaqueID(s string) func(*MLValidateDetectorRequest) {
+	return func(r *MLValidateDetectorRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.monitoring.bulk.go b/esapi/api.xpack.monitoring.bulk.go
new file mode 100644
index 0000000000..094b4ff40d
--- /dev/null
+++ b/esapi/api.xpack.monitoring.bulk.go
@@ -0,0 +1,260 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newMonitoringBulkFunc(t Transport) MonitoringBulk {
+	return func(body io.Reader, o ...func(*MonitoringBulkRequest)) (*Response, error) {
+		var r = MonitoringBulkRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// MonitoringBulk - Used by the monitoring features to send monitoring data.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/monitor-elasticsearch-cluster.html.
+//
+type MonitoringBulk func(body io.Reader, o ...func(*MonitoringBulkRequest)) (*Response, error)
+
+// MonitoringBulkRequest configures the Monitoring Bulk API request.
+//
+type MonitoringBulkRequest struct {
+	DocumentType string
+
+	Body io.Reader
+
+	Interval         string
+	SystemAPIVersion string
+	SystemID         string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r MonitoringBulkRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_monitoring") + 1 + len(r.DocumentType) + 1 + len("bulk"))
+	path.WriteString("/")
+	path.WriteString("_monitoring")
+	if r.DocumentType != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentType)
+	}
+	path.WriteString("/")
+	path.WriteString("bulk")
+
+	params = make(map[string]string)
+
+	if r.Interval != "" {
+		params["interval"] = r.Interval
+	}
+
+	if r.SystemAPIVersion != "" {
+		params["system_api_version"] = r.SystemAPIVersion
+	}
+
+	if r.SystemID != "" {
+		params["system_id"] = r.SystemID
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f MonitoringBulk) WithContext(v context.Context) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDocumentType - default document type for items which don't provide one.
+//
+func (f MonitoringBulk) WithDocumentType(v string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.DocumentType = v
+	}
+}
+
+// WithInterval - collection interval (e.g., '10s' or '10000ms') of the payload.
+//
+func (f MonitoringBulk) WithInterval(v string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.Interval = v
+	}
+}
+
+// WithSystemAPIVersion - api version of the monitored system.
+//
+func (f MonitoringBulk) WithSystemAPIVersion(v string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.SystemAPIVersion = v
+	}
+}
+
+// WithSystemID - identifier of the monitored system.
+//
+func (f MonitoringBulk) WithSystemID(v string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.SystemID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f MonitoringBulk) WithPretty() func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f MonitoringBulk) WithHuman() func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f MonitoringBulk) WithErrorTrace() func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f MonitoringBulk) WithFilterPath(v ...string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f MonitoringBulk) WithHeader(h map[string]string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f MonitoringBulk) WithOpaqueID(s string) func(*MonitoringBulkRequest) {
+	return func(r *MonitoringBulkRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.open_point_in_time.go b/esapi/api.xpack.open_point_in_time.go
new file mode 100644
index 0000000000..b1cb2b11b4
--- /dev/null
+++ b/esapi/api.xpack.open_point_in_time.go
@@ -0,0 +1,268 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newOpenPointInTimeFunc(t Transport) OpenPointInTime {
+	return func(index []string, keep_alive string, o ...func(*OpenPointInTimeRequest)) (*Response, error) {
+		var r = OpenPointInTimeRequest{Index: index, KeepAlive: keep_alive}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// OpenPointInTime - Open a point in time that can be used in subsequent searches
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/point-in-time-api.html.
+//
+type OpenPointInTime func(index []string, keep_alive string, o ...func(*OpenPointInTimeRequest)) (*Response, error)
+
+// OpenPointInTimeRequest configures the Open Point In Time API request.
+//
+type OpenPointInTimeRequest struct {
+	Index []string
+
+	ExpandWildcards   string
+	IgnoreUnavailable *bool
+	KeepAlive         string
+	Preference        string
+	Routing           string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r OpenPointInTimeRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_pit"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	path.WriteString("/")
+	path.WriteString("_pit")
+
+	params = make(map[string]string)
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if r.KeepAlive != "" {
+		params["keep_alive"] = r.KeepAlive
+	}
+
+	if r.Preference != "" {
+		params["preference"] = r.Preference
+	}
+
+	if r.Routing != "" {
+		params["routing"] = r.Routing
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f OpenPointInTime) WithContext(v context.Context) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.ctx = v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f OpenPointInTime) WithExpandWildcards(v string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f OpenPointInTime) WithIgnoreUnavailable(v bool) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithKeepAlive - specific the time to live for the point in time.
+//
+func (f OpenPointInTime) WithKeepAlive(v string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithPreference - specify the node or shard the operation should be performed on (default: random).
+//
+func (f OpenPointInTime) WithPreference(v string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.Preference = v
+	}
+}
+
+// WithRouting - specific routing value.
+//
+func (f OpenPointInTime) WithRouting(v string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.Routing = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f OpenPointInTime) WithPretty() func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f OpenPointInTime) WithHuman() func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f OpenPointInTime) WithErrorTrace() func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f OpenPointInTime) WithFilterPath(v ...string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f OpenPointInTime) WithHeader(h map[string]string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f OpenPointInTime) WithOpaqueID(s string) func(*OpenPointInTimeRequest) {
+	return func(r *OpenPointInTimeRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.delete_job.go b/esapi/api.xpack.rollup.delete_job.go
new file mode 100644
index 0000000000..bbeaa02905
--- /dev/null
+++ b/esapi/api.xpack.rollup.delete_job.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newRollupDeleteJobFunc(t Transport) RollupDeleteJob {
+	return func(id string, o ...func(*RollupDeleteJobRequest)) (*Response, error) {
+		var r = RollupDeleteJobRequest{JobID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupDeleteJob - Deletes an existing rollup job.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-delete-job.html.
+//
+type RollupDeleteJob func(id string, o ...func(*RollupDeleteJobRequest)) (*Response, error)
+
+// RollupDeleteJobRequest configures the Rollup Delete Job API request.
+//
+type RollupDeleteJobRequest struct {
+	JobID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupDeleteJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_rollup") + 1 + len("job") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("job")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupDeleteJob) WithContext(v context.Context) func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupDeleteJob) WithPretty() func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupDeleteJob) WithHuman() func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupDeleteJob) WithErrorTrace() func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupDeleteJob) WithFilterPath(v ...string) func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupDeleteJob) WithHeader(h map[string]string) func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupDeleteJob) WithOpaqueID(s string) func(*RollupDeleteJobRequest) {
+	return func(r *RollupDeleteJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.get_jobs.go b/esapi/api.xpack.rollup.get_jobs.go
new file mode 100644
index 0000000000..2a8697825b
--- /dev/null
+++ b/esapi/api.xpack.rollup.get_jobs.go
@@ -0,0 +1,215 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newRollupGetJobsFunc(t Transport) RollupGetJobs {
+	return func(o ...func(*RollupGetJobsRequest)) (*Response, error) {
+		var r = RollupGetJobsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupGetJobs - Retrieves the configuration, stats, and status of rollup jobs.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-get-job.html.
+//
+type RollupGetJobs func(o ...func(*RollupGetJobsRequest)) (*Response, error)
+
+// RollupGetJobsRequest configures the Rollup Get Jobs API request.
+//
+type RollupGetJobsRequest struct {
+	JobID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupGetJobsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_rollup") + 1 + len("job") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("job")
+	if r.JobID != "" {
+		path.WriteString("/")
+		path.WriteString(r.JobID)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupGetJobs) WithContext(v context.Context) func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithJobID - the ID of the job(s) to fetch. accepts glob patterns, or left blank for all jobs.
+//
+func (f RollupGetJobs) WithJobID(v string) func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.JobID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupGetJobs) WithPretty() func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupGetJobs) WithHuman() func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupGetJobs) WithErrorTrace() func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupGetJobs) WithFilterPath(v ...string) func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupGetJobs) WithHeader(h map[string]string) func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupGetJobs) WithOpaqueID(s string) func(*RollupGetJobsRequest) {
+	return func(r *RollupGetJobsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.get_rollup_caps.go b/esapi/api.xpack.rollup.get_rollup_caps.go
new file mode 100644
index 0000000000..160f8bb8d0
--- /dev/null
+++ b/esapi/api.xpack.rollup.get_rollup_caps.go
@@ -0,0 +1,215 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newRollupGetRollupCapsFunc(t Transport) RollupGetRollupCaps {
+	return func(o ...func(*RollupGetRollupCapsRequest)) (*Response, error) {
+		var r = RollupGetRollupCapsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupGetRollupCaps - Returns the capabilities of any rollup jobs that have been configured for a specific index or index pattern.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-get-rollup-caps.html.
+//
+type RollupGetRollupCaps func(o ...func(*RollupGetRollupCapsRequest)) (*Response, error)
+
+// RollupGetRollupCapsRequest configures the Rollup Get Rollup Caps API request.
+//
+type RollupGetRollupCapsRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupGetRollupCapsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_rollup") + 1 + len("data") + 1 + len(r.Index))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("data")
+	if r.Index != "" {
+		path.WriteString("/")
+		path.WriteString(r.Index)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupGetRollupCaps) WithContext(v context.Context) func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithIndex - the ID of the index to check rollup capabilities on, or left blank for all jobs.
+//
+func (f RollupGetRollupCaps) WithIndex(v string) func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.Index = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupGetRollupCaps) WithPretty() func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupGetRollupCaps) WithHuman() func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupGetRollupCaps) WithErrorTrace() func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupGetRollupCaps) WithFilterPath(v ...string) func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupGetRollupCaps) WithHeader(h map[string]string) func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupGetRollupCaps) WithOpaqueID(s string) func(*RollupGetRollupCapsRequest) {
+	return func(r *RollupGetRollupCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.get_rollup_index_caps.go b/esapi/api.xpack.rollup.get_rollup_index_caps.go
new file mode 100644
index 0000000000..f7d5a49ddf
--- /dev/null
+++ b/esapi/api.xpack.rollup.get_rollup_index_caps.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newRollupGetRollupIndexCapsFunc(t Transport) RollupGetRollupIndexCaps {
+	return func(index string, o ...func(*RollupGetRollupIndexCapsRequest)) (*Response, error) {
+		var r = RollupGetRollupIndexCapsRequest{Index: index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupGetRollupIndexCaps - Returns the rollup capabilities of all jobs inside of a rollup index (e.g. the index where rollup data is stored).
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-get-rollup-index-caps.html.
+//
+type RollupGetRollupIndexCaps func(index string, o ...func(*RollupGetRollupIndexCapsRequest)) (*Response, error)
+
+// RollupGetRollupIndexCapsRequest configures the Rollup Get Rollup Index Caps API request.
+//
+type RollupGetRollupIndexCapsRequest struct {
+	Index string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupGetRollupIndexCapsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_rollup") + 1 + len("data"))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("data")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupGetRollupIndexCaps) WithContext(v context.Context) func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupGetRollupIndexCaps) WithPretty() func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupGetRollupIndexCaps) WithHuman() func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupGetRollupIndexCaps) WithErrorTrace() func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupGetRollupIndexCaps) WithFilterPath(v ...string) func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupGetRollupIndexCaps) WithHeader(h map[string]string) func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupGetRollupIndexCaps) WithOpaqueID(s string) func(*RollupGetRollupIndexCapsRequest) {
+	return func(r *RollupGetRollupIndexCapsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.put_job.go b/esapi/api.xpack.rollup.put_job.go
new file mode 100644
index 0000000000..0f8d54185f
--- /dev/null
+++ b/esapi/api.xpack.rollup.put_job.go
@@ -0,0 +1,212 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newRollupPutJobFunc(t Transport) RollupPutJob {
+	return func(id string, body io.Reader, o ...func(*RollupPutJobRequest)) (*Response, error) {
+		var r = RollupPutJobRequest{JobID: id, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupPutJob - Creates a rollup job.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-put-job.html.
+//
+type RollupPutJob func(id string, body io.Reader, o ...func(*RollupPutJobRequest)) (*Response, error)
+
+// RollupPutJobRequest configures the Rollup Put Job API request.
+//
+type RollupPutJobRequest struct {
+	JobID string
+
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupPutJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_rollup") + 1 + len("job") + 1 + len(r.JobID))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("job")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupPutJob) WithContext(v context.Context) func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupPutJob) WithPretty() func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupPutJob) WithHuman() func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupPutJob) WithErrorTrace() func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupPutJob) WithFilterPath(v ...string) func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupPutJob) WithHeader(h map[string]string) func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupPutJob) WithOpaqueID(s string) func(*RollupPutJobRequest) {
+	return func(r *RollupPutJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.rollup.go b/esapi/api.xpack.rollup.rollup.go
new file mode 100644
index 0000000000..dfbc90b1c1
--- /dev/null
+++ b/esapi/api.xpack.rollup.rollup.go
@@ -0,0 +1,214 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newRollupRollupFunc(t Transport) RollupRollup {
+	return func(index string, body io.Reader, rollup_index string, o ...func(*RollupRollupRequest)) (*Response, error) {
+		var r = RollupRollupRequest{Index: index, Body: body, RollupIndex: rollup_index}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupRollup - Rollup an index
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/xpack-rollup.html.
+//
+type RollupRollup func(index string, body io.Reader, rollup_index string, o ...func(*RollupRollupRequest)) (*Response, error)
+
+// RollupRollupRequest configures the Rollup Rollup API request.
+//
+type RollupRollupRequest struct {
+	Index string
+
+	Body io.Reader
+
+	RollupIndex string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupRollupRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(r.Index) + 1 + len("_rollup") + 1 + len(r.RollupIndex))
+	path.WriteString("/")
+	path.WriteString(r.Index)
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString(r.RollupIndex)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupRollup) WithContext(v context.Context) func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupRollup) WithPretty() func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupRollup) WithHuman() func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupRollup) WithErrorTrace() func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupRollup) WithFilterPath(v ...string) func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupRollup) WithHeader(h map[string]string) func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupRollup) WithOpaqueID(s string) func(*RollupRollupRequest) {
+	return func(r *RollupRollupRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.rollup_search.go b/esapi/api.xpack.rollup.rollup_search.go
new file mode 100644
index 0000000000..41e7084b42
--- /dev/null
+++ b/esapi/api.xpack.rollup.rollup_search.go
@@ -0,0 +1,251 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newRollupRollupSearchFunc(t Transport) RollupRollupSearch {
+	return func(index []string, body io.Reader, o ...func(*RollupRollupSearchRequest)) (*Response, error) {
+		var r = RollupRollupSearchRequest{Index: index, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupRollupSearch - Enables searching rolled-up data using the standard query DSL.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-search.html.
+//
+type RollupRollupSearch func(index []string, body io.Reader, o ...func(*RollupRollupSearchRequest)) (*Response, error)
+
+// RollupRollupSearchRequest configures the Rollup Rollup Search API request.
+//
+type RollupRollupSearchRequest struct {
+	Index        []string
+	DocumentType string
+
+	Body io.Reader
+
+	RestTotalHitsAsInt *bool
+	TypedKeys          *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupRollupSearchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len(r.DocumentType) + 1 + len("_rollup_search"))
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Index, ","))
+	if r.DocumentType != "" {
+		path.WriteString("/")
+		path.WriteString(r.DocumentType)
+	}
+	path.WriteString("/")
+	path.WriteString("_rollup_search")
+
+	params = make(map[string]string)
+
+	if r.RestTotalHitsAsInt != nil {
+		params["rest_total_hits_as_int"] = strconv.FormatBool(*r.RestTotalHitsAsInt)
+	}
+
+	if r.TypedKeys != nil {
+		params["typed_keys"] = strconv.FormatBool(*r.TypedKeys)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupRollupSearch) WithContext(v context.Context) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDocumentType - the doc type inside the index.
+//
+func (f RollupRollupSearch) WithDocumentType(v string) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.DocumentType = v
+	}
+}
+
+// WithRestTotalHitsAsInt - indicates whether hits.total should be rendered as an integer or an object in the rest search response.
+//
+func (f RollupRollupSearch) WithRestTotalHitsAsInt(v bool) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.RestTotalHitsAsInt = &v
+	}
+}
+
+// WithTypedKeys - specify whether aggregation and suggester names should be prefixed by their respective types in the response.
+//
+func (f RollupRollupSearch) WithTypedKeys(v bool) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.TypedKeys = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupRollupSearch) WithPretty() func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupRollupSearch) WithHuman() func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupRollupSearch) WithErrorTrace() func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupRollupSearch) WithFilterPath(v ...string) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupRollupSearch) WithHeader(h map[string]string) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupRollupSearch) WithOpaqueID(s string) func(*RollupRollupSearchRequest) {
+	return func(r *RollupRollupSearchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.start_job.go b/esapi/api.xpack.rollup.start_job.go
new file mode 100644
index 0000000000..9948f40a70
--- /dev/null
+++ b/esapi/api.xpack.rollup.start_job.go
@@ -0,0 +1,207 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newRollupStartJobFunc(t Transport) RollupStartJob {
+	return func(id string, o ...func(*RollupStartJobRequest)) (*Response, error) {
+		var r = RollupStartJobRequest{JobID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupStartJob - Starts an existing, stopped rollup job.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-start-job.html.
+//
+type RollupStartJob func(id string, o ...func(*RollupStartJobRequest)) (*Response, error)
+
+// RollupStartJobRequest configures the Rollup Start Job API request.
+//
+type RollupStartJobRequest struct {
+	JobID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupStartJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_rollup") + 1 + len("job") + 1 + len(r.JobID) + 1 + len("_start"))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("job")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_start")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupStartJob) WithContext(v context.Context) func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupStartJob) WithPretty() func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupStartJob) WithHuman() func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupStartJob) WithErrorTrace() func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupStartJob) WithFilterPath(v ...string) func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupStartJob) WithHeader(h map[string]string) func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupStartJob) WithOpaqueID(s string) func(*RollupStartJobRequest) {
+	return func(r *RollupStartJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.rollup.stop_job.go b/esapi/api.xpack.rollup.stop_job.go
new file mode 100644
index 0000000000..0941652892
--- /dev/null
+++ b/esapi/api.xpack.rollup.stop_job.go
@@ -0,0 +1,236 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newRollupStopJobFunc(t Transport) RollupStopJob {
+	return func(id string, o ...func(*RollupStopJobRequest)) (*Response, error) {
+		var r = RollupStopJobRequest{JobID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// RollupStopJob - Stops an existing, started rollup job.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/rollup-stop-job.html.
+//
+type RollupStopJob func(id string, o ...func(*RollupStopJobRequest)) (*Response, error)
+
+// RollupStopJobRequest configures the Rollup Stop Job API request.
+//
+type RollupStopJobRequest struct {
+	JobID string
+
+	Timeout           time.Duration
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r RollupStopJobRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_rollup") + 1 + len("job") + 1 + len(r.JobID) + 1 + len("_stop"))
+	path.WriteString("/")
+	path.WriteString("_rollup")
+	path.WriteString("/")
+	path.WriteString("job")
+	path.WriteString("/")
+	path.WriteString(r.JobID)
+	path.WriteString("/")
+	path.WriteString("_stop")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f RollupStopJob) WithContext(v context.Context) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTimeout - block for (at maximum) the specified duration while waiting for the job to stop.  defaults to 30s..
+//
+func (f RollupStopJob) WithTimeout(v time.Duration) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForCompletion - true if the api should block until the job has fully stopped, false if should be executed async. defaults to false..
+//
+func (f RollupStopJob) WithWaitForCompletion(v bool) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f RollupStopJob) WithPretty() func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f RollupStopJob) WithHuman() func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f RollupStopJob) WithErrorTrace() func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f RollupStopJob) WithFilterPath(v ...string) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f RollupStopJob) WithHeader(h map[string]string) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f RollupStopJob) WithOpaqueID(s string) func(*RollupStopJobRequest) {
+	return func(r *RollupStopJobRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.searchable_snapshots.cache_stats.go b/esapi/api.xpack.searchable_snapshots.cache_stats.go
new file mode 100644
index 0000000000..dc1fc82465
--- /dev/null
+++ b/esapi/api.xpack.searchable_snapshots.cache_stats.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSearchableSnapshotsCacheStatsFunc(t Transport) SearchableSnapshotsCacheStats {
+	return func(o ...func(*SearchableSnapshotsCacheStatsRequest)) (*Response, error) {
+		var r = SearchableSnapshotsCacheStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchableSnapshotsCacheStats - Retrieve node-level cache statistics about searchable snapshots.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/searchable-snapshots-apis.html.
+//
+type SearchableSnapshotsCacheStats func(o ...func(*SearchableSnapshotsCacheStatsRequest)) (*Response, error)
+
+// SearchableSnapshotsCacheStatsRequest configures the Searchable Snapshots Cache Stats API request.
+//
+type SearchableSnapshotsCacheStatsRequest struct {
+	NodeID []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchableSnapshotsCacheStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_searchable_snapshots") + 1 + len(strings.Join(r.NodeID, ",")) + 1 + len("cache") + 1 + len("stats"))
+	path.WriteString("/")
+	path.WriteString("_searchable_snapshots")
+	if len(r.NodeID) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.NodeID, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("cache")
+	path.WriteString("/")
+	path.WriteString("stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchableSnapshotsCacheStats) WithContext(v context.Context) func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithNodeID - a list of node ids or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
+//
+func (f SearchableSnapshotsCacheStats) WithNodeID(v ...string) func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.NodeID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchableSnapshotsCacheStats) WithPretty() func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchableSnapshotsCacheStats) WithHuman() func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchableSnapshotsCacheStats) WithErrorTrace() func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchableSnapshotsCacheStats) WithFilterPath(v ...string) func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchableSnapshotsCacheStats) WithHeader(h map[string]string) func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchableSnapshotsCacheStats) WithOpaqueID(s string) func(*SearchableSnapshotsCacheStatsRequest) {
+	return func(r *SearchableSnapshotsCacheStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.searchable_snapshots.clear_cache.go b/esapi/api.xpack.searchable_snapshots.clear_cache.go
new file mode 100644
index 0000000000..118f2c86a0
--- /dev/null
+++ b/esapi/api.xpack.searchable_snapshots.clear_cache.go
@@ -0,0 +1,262 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newSearchableSnapshotsClearCacheFunc(t Transport) SearchableSnapshotsClearCache {
+	return func(o ...func(*SearchableSnapshotsClearCacheRequest)) (*Response, error) {
+		var r = SearchableSnapshotsClearCacheRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchableSnapshotsClearCache - Clear the cache of searchable snapshots.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-apis.html.
+//
+type SearchableSnapshotsClearCache func(o ...func(*SearchableSnapshotsClearCacheRequest)) (*Response, error)
+
+// SearchableSnapshotsClearCacheRequest configures the Searchable Snapshots Clear Cache API request.
+//
+type SearchableSnapshotsClearCacheRequest struct {
+	Index []string
+
+	AllowNoIndices    *bool
+	ExpandWildcards   string
+	IgnoreUnavailable *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchableSnapshotsClearCacheRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_searchable_snapshots") + 1 + len("cache") + 1 + len("clear"))
+	if len(r.Index) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Index, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("_searchable_snapshots")
+	path.WriteString("/")
+	path.WriteString("cache")
+	path.WriteString("/")
+	path.WriteString("clear")
+
+	params = make(map[string]string)
+
+	if r.AllowNoIndices != nil {
+		params["allow_no_indices"] = strconv.FormatBool(*r.AllowNoIndices)
+	}
+
+	if r.ExpandWildcards != "" {
+		params["expand_wildcards"] = r.ExpandWildcards
+	}
+
+	if r.IgnoreUnavailable != nil {
+		params["ignore_unavailable"] = strconv.FormatBool(*r.IgnoreUnavailable)
+	}
+
+	if len(r.Index) > 0 {
+		params["index"] = strings.Join(r.Index, ",")
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchableSnapshotsClearCache) WithContext(v context.Context) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.ctx = v
+	}
+}
+
+// WithIndex - a list of index names.
+//
+func (f SearchableSnapshotsClearCache) WithIndex(v ...string) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.Index = v
+	}
+}
+
+// WithAllowNoIndices - whether to ignore if a wildcard indices expression resolves into no concrete indices. (this includes `_all` string or when no indices have been specified).
+//
+func (f SearchableSnapshotsClearCache) WithAllowNoIndices(v bool) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.AllowNoIndices = &v
+	}
+}
+
+// WithExpandWildcards - whether to expand wildcard expression to concrete indices that are open, closed or both..
+//
+func (f SearchableSnapshotsClearCache) WithExpandWildcards(v string) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.ExpandWildcards = v
+	}
+}
+
+// WithIgnoreUnavailable - whether specified concrete indices should be ignored when unavailable (missing or closed).
+//
+func (f SearchableSnapshotsClearCache) WithIgnoreUnavailable(v bool) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.IgnoreUnavailable = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchableSnapshotsClearCache) WithPretty() func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchableSnapshotsClearCache) WithHuman() func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchableSnapshotsClearCache) WithErrorTrace() func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchableSnapshotsClearCache) WithFilterPath(v ...string) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchableSnapshotsClearCache) WithHeader(h map[string]string) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchableSnapshotsClearCache) WithOpaqueID(s string) func(*SearchableSnapshotsClearCacheRequest) {
+	return func(r *SearchableSnapshotsClearCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.searchable_snapshots.mount.go b/esapi/api.xpack.searchable_snapshots.mount.go
new file mode 100644
index 0000000000..cf1b050cf0
--- /dev/null
+++ b/esapi/api.xpack.searchable_snapshots.mount.go
@@ -0,0 +1,255 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newSearchableSnapshotsMountFunc(t Transport) SearchableSnapshotsMount {
+	return func(repository string, snapshot string, body io.Reader, o ...func(*SearchableSnapshotsMountRequest)) (*Response, error) {
+		var r = SearchableSnapshotsMountRequest{Repository: repository, Snapshot: snapshot, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchableSnapshotsMount - Mount a snapshot as a searchable index.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-api-mount-snapshot.html.
+//
+type SearchableSnapshotsMount func(repository string, snapshot string, body io.Reader, o ...func(*SearchableSnapshotsMountRequest)) (*Response, error)
+
+// SearchableSnapshotsMountRequest configures the Searchable Snapshots Mount API request.
+//
+type SearchableSnapshotsMountRequest struct {
+	Body io.Reader
+
+	Repository string
+	Snapshot   string
+
+	MasterTimeout     time.Duration
+	Storage           string
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchableSnapshotsMountRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_snapshot") + 1 + len(r.Repository) + 1 + len(r.Snapshot) + 1 + len("_mount"))
+	path.WriteString("/")
+	path.WriteString("_snapshot")
+	path.WriteString("/")
+	path.WriteString(r.Repository)
+	path.WriteString("/")
+	path.WriteString(r.Snapshot)
+	path.WriteString("/")
+	path.WriteString("_mount")
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Storage != "" {
+		params["storage"] = r.Storage
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchableSnapshotsMount) WithContext(v context.Context) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - explicit operation timeout for connection to master node.
+//
+func (f SearchableSnapshotsMount) WithMasterTimeout(v time.Duration) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithStorage - selects the kind of local storage used to accelerate searches. experimental, and defaults to `full_copy`.
+//
+func (f SearchableSnapshotsMount) WithStorage(v string) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.Storage = v
+	}
+}
+
+// WithWaitForCompletion - should this request wait until the operation has completed before returning.
+//
+func (f SearchableSnapshotsMount) WithWaitForCompletion(v bool) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchableSnapshotsMount) WithPretty() func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchableSnapshotsMount) WithHuman() func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchableSnapshotsMount) WithErrorTrace() func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchableSnapshotsMount) WithFilterPath(v ...string) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchableSnapshotsMount) WithHeader(h map[string]string) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchableSnapshotsMount) WithOpaqueID(s string) func(*SearchableSnapshotsMountRequest) {
+	return func(r *SearchableSnapshotsMountRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.searchable_snapshots.repository_stats.go b/esapi/api.xpack.searchable_snapshots.repository_stats.go
new file mode 100644
index 0000000000..bf59451939
--- /dev/null
+++ b/esapi/api.xpack.searchable_snapshots.repository_stats.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSearchableSnapshotsRepositoryStatsFunc(t Transport) SearchableSnapshotsRepositoryStats {
+	return func(repository string, o ...func(*SearchableSnapshotsRepositoryStatsRequest)) (*Response, error) {
+		var r = SearchableSnapshotsRepositoryStatsRequest{Repository: repository}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchableSnapshotsRepositoryStats - DEPRECATED: This API is replaced by the Repositories Metering API.
+//
+// This API is experimental.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-apis.html.
+//
+type SearchableSnapshotsRepositoryStats func(repository string, o ...func(*SearchableSnapshotsRepositoryStatsRequest)) (*Response, error)
+
+// SearchableSnapshotsRepositoryStatsRequest configures the Searchable Snapshots Repository Stats API request.
+//
+type SearchableSnapshotsRepositoryStatsRequest struct {
+	Repository string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchableSnapshotsRepositoryStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_snapshot") + 1 + len(r.Repository) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_snapshot")
+	path.WriteString("/")
+	path.WriteString(r.Repository)
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchableSnapshotsRepositoryStats) WithContext(v context.Context) func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchableSnapshotsRepositoryStats) WithPretty() func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchableSnapshotsRepositoryStats) WithHuman() func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchableSnapshotsRepositoryStats) WithErrorTrace() func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchableSnapshotsRepositoryStats) WithFilterPath(v ...string) func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchableSnapshotsRepositoryStats) WithHeader(h map[string]string) func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchableSnapshotsRepositoryStats) WithOpaqueID(s string) func(*SearchableSnapshotsRepositoryStatsRequest) {
+	return func(r *SearchableSnapshotsRepositoryStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.searchable_snapshots.stats.go b/esapi/api.xpack.searchable_snapshots.stats.go
new file mode 100644
index 0000000000..4e5d670d1c
--- /dev/null
+++ b/esapi/api.xpack.searchable_snapshots.stats.go
@@ -0,0 +1,227 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSearchableSnapshotsStatsFunc(t Transport) SearchableSnapshotsStats {
+	return func(o ...func(*SearchableSnapshotsStatsRequest)) (*Response, error) {
+		var r = SearchableSnapshotsStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SearchableSnapshotsStats - Retrieve shard-level statistics about searchable snapshots.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/searchable-snapshots-apis.html.
+//
+type SearchableSnapshotsStats func(o ...func(*SearchableSnapshotsStatsRequest)) (*Response, error)
+
+// SearchableSnapshotsStatsRequest configures the Searchable Snapshots Stats API request.
+//
+type SearchableSnapshotsStatsRequest struct {
+	Index []string
+
+	Level string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SearchableSnapshotsStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len(strings.Join(r.Index, ",")) + 1 + len("_searchable_snapshots") + 1 + len("stats"))
+	if len(r.Index) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Index, ","))
+	}
+	path.WriteString("/")
+	path.WriteString("_searchable_snapshots")
+	path.WriteString("/")
+	path.WriteString("stats")
+
+	params = make(map[string]string)
+
+	if r.Level != "" {
+		params["level"] = r.Level
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SearchableSnapshotsStats) WithContext(v context.Context) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithIndex - a list of index names.
+//
+func (f SearchableSnapshotsStats) WithIndex(v ...string) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.Index = v
+	}
+}
+
+// WithLevel - return stats aggregated at cluster, index or shard level.
+//
+func (f SearchableSnapshotsStats) WithLevel(v string) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.Level = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SearchableSnapshotsStats) WithPretty() func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SearchableSnapshotsStats) WithHuman() func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SearchableSnapshotsStats) WithErrorTrace() func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SearchableSnapshotsStats) WithFilterPath(v ...string) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SearchableSnapshotsStats) WithHeader(h map[string]string) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SearchableSnapshotsStats) WithOpaqueID(s string) func(*SearchableSnapshotsStatsRequest) {
+	return func(r *SearchableSnapshotsStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.authenticate.go b/esapi/api.xpack.security.authenticate.go
new file mode 100644
index 0000000000..1eea36dfc4
--- /dev/null
+++ b/esapi/api.xpack.security.authenticate.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityAuthenticateFunc(t Transport) SecurityAuthenticate {
+	return func(o ...func(*SecurityAuthenticateRequest)) (*Response, error) {
+		var r = SecurityAuthenticateRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityAuthenticate - Enables authentication as a user and retrieve information about the authenticated user.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html.
+//
+type SecurityAuthenticate func(o ...func(*SecurityAuthenticateRequest)) (*Response, error)
+
+// SecurityAuthenticateRequest configures the Security Authenticate API request.
+//
+type SecurityAuthenticateRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityAuthenticateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_security/_authenticate"))
+	path.WriteString("/_security/_authenticate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityAuthenticate) WithContext(v context.Context) func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityAuthenticate) WithPretty() func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityAuthenticate) WithHuman() func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityAuthenticate) WithErrorTrace() func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityAuthenticate) WithFilterPath(v ...string) func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityAuthenticate) WithHeader(h map[string]string) func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityAuthenticate) WithOpaqueID(s string) func(*SecurityAuthenticateRequest) {
+	return func(r *SecurityAuthenticateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.change_password.go b/esapi/api.xpack.security.change_password.go
new file mode 100644
index 0000000000..a56b9c331f
--- /dev/null
+++ b/esapi/api.xpack.security.change_password.go
@@ -0,0 +1,236 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityChangePasswordFunc(t Transport) SecurityChangePassword {
+	return func(body io.Reader, o ...func(*SecurityChangePasswordRequest)) (*Response, error) {
+		var r = SecurityChangePasswordRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityChangePassword - Changes the passwords of users in the native realm and built-in users.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-change-password.html.
+//
+type SecurityChangePassword func(body io.Reader, o ...func(*SecurityChangePasswordRequest)) (*Response, error)
+
+// SecurityChangePasswordRequest configures the Security Change Password API request.
+//
+type SecurityChangePasswordRequest struct {
+	Body io.Reader
+
+	Username string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityChangePasswordRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.Username) + 1 + len("_password"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	if r.Username != "" {
+		path.WriteString("/")
+		path.WriteString(r.Username)
+	}
+	path.WriteString("/")
+	path.WriteString("_password")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityChangePassword) WithContext(v context.Context) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.ctx = v
+	}
+}
+
+// WithUsername - the username of the user to change the password for.
+//
+func (f SecurityChangePassword) WithUsername(v string) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.Username = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityChangePassword) WithRefresh(v string) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityChangePassword) WithPretty() func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityChangePassword) WithHuman() func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityChangePassword) WithErrorTrace() func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityChangePassword) WithFilterPath(v ...string) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityChangePassword) WithHeader(h map[string]string) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityChangePassword) WithOpaqueID(s string) func(*SecurityChangePasswordRequest) {
+	return func(r *SecurityChangePasswordRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.clear_api_key_cache.go b/esapi/api.xpack.security.clear_api_key_cache.go
new file mode 100644
index 0000000000..7cf6f0cb51
--- /dev/null
+++ b/esapi/api.xpack.security.clear_api_key_cache.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityClearAPIKeyCacheFunc(t Transport) SecurityClearAPIKeyCache {
+	return func(ids []string, o ...func(*SecurityClearAPIKeyCacheRequest)) (*Response, error) {
+		var r = SecurityClearAPIKeyCacheRequest{Ids: ids}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityClearAPIKeyCache - Clear a subset or all entries from the API key cache.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-api-key-cache.html.
+//
+type SecurityClearAPIKeyCache func(ids []string, o ...func(*SecurityClearAPIKeyCacheRequest)) (*Response, error)
+
+// SecurityClearAPIKeyCacheRequest configures the Security ClearAPI Key Cache API request.
+//
+type SecurityClearAPIKeyCacheRequest struct {
+	Ids []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityClearAPIKeyCacheRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("api_key") + 1 + len(strings.Join(r.Ids, ",")) + 1 + len("_clear_cache"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("api_key")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Ids, ","))
+	path.WriteString("/")
+	path.WriteString("_clear_cache")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityClearAPIKeyCache) WithContext(v context.Context) func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityClearAPIKeyCache) WithPretty() func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityClearAPIKeyCache) WithHuman() func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityClearAPIKeyCache) WithErrorTrace() func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityClearAPIKeyCache) WithFilterPath(v ...string) func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityClearAPIKeyCache) WithHeader(h map[string]string) func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityClearAPIKeyCache) WithOpaqueID(s string) func(*SecurityClearAPIKeyCacheRequest) {
+	return func(r *SecurityClearAPIKeyCacheRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.clear_cached_privileges.go b/esapi/api.xpack.security.clear_cached_privileges.go
new file mode 100644
index 0000000000..6cef799af7
--- /dev/null
+++ b/esapi/api.xpack.security.clear_cached_privileges.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityClearCachedPrivilegesFunc(t Transport) SecurityClearCachedPrivileges {
+	return func(application []string, o ...func(*SecurityClearCachedPrivilegesRequest)) (*Response, error) {
+		var r = SecurityClearCachedPrivilegesRequest{Application: application}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityClearCachedPrivileges - Evicts application privileges from the native application privileges cache.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-privilege-cache.html.
+//
+type SecurityClearCachedPrivileges func(application []string, o ...func(*SecurityClearCachedPrivilegesRequest)) (*Response, error)
+
+// SecurityClearCachedPrivilegesRequest configures the Security Clear Cached Privileges API request.
+//
+type SecurityClearCachedPrivilegesRequest struct {
+	Application []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityClearCachedPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("privilege") + 1 + len(strings.Join(r.Application, ",")) + 1 + len("_clear_cache"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("privilege")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Application, ","))
+	path.WriteString("/")
+	path.WriteString("_clear_cache")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityClearCachedPrivileges) WithContext(v context.Context) func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityClearCachedPrivileges) WithPretty() func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityClearCachedPrivileges) WithHuman() func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityClearCachedPrivileges) WithErrorTrace() func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityClearCachedPrivileges) WithFilterPath(v ...string) func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityClearCachedPrivileges) WithHeader(h map[string]string) func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityClearCachedPrivileges) WithOpaqueID(s string) func(*SecurityClearCachedPrivilegesRequest) {
+	return func(r *SecurityClearCachedPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.clear_cached_realms.go b/esapi/api.xpack.security.clear_cached_realms.go
new file mode 100644
index 0000000000..a8762bd910
--- /dev/null
+++ b/esapi/api.xpack.security.clear_cached_realms.go
@@ -0,0 +1,219 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityClearCachedRealmsFunc(t Transport) SecurityClearCachedRealms {
+	return func(realms []string, o ...func(*SecurityClearCachedRealmsRequest)) (*Response, error) {
+		var r = SecurityClearCachedRealmsRequest{Realms: realms}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityClearCachedRealms - Evicts users from the user cache. Can completely clear the cache or evict specific users.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-cache.html.
+//
+type SecurityClearCachedRealms func(realms []string, o ...func(*SecurityClearCachedRealmsRequest)) (*Response, error)
+
+// SecurityClearCachedRealmsRequest configures the Security Clear Cached Realms API request.
+//
+type SecurityClearCachedRealmsRequest struct {
+	Realms []string
+
+	Usernames []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityClearCachedRealmsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("realm") + 1 + len(strings.Join(r.Realms, ",")) + 1 + len("_clear_cache"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("realm")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Realms, ","))
+	path.WriteString("/")
+	path.WriteString("_clear_cache")
+
+	params = make(map[string]string)
+
+	if len(r.Usernames) > 0 {
+		params["usernames"] = strings.Join(r.Usernames, ",")
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityClearCachedRealms) WithContext(v context.Context) func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithUsernames - comma-separated list of usernames to clear from the cache.
+//
+func (f SecurityClearCachedRealms) WithUsernames(v ...string) func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.Usernames = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityClearCachedRealms) WithPretty() func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityClearCachedRealms) WithHuman() func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityClearCachedRealms) WithErrorTrace() func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityClearCachedRealms) WithFilterPath(v ...string) func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityClearCachedRealms) WithHeader(h map[string]string) func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityClearCachedRealms) WithOpaqueID(s string) func(*SecurityClearCachedRealmsRequest) {
+	return func(r *SecurityClearCachedRealmsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.clear_cached_roles.go b/esapi/api.xpack.security.clear_cached_roles.go
new file mode 100644
index 0000000000..f21287c54b
--- /dev/null
+++ b/esapi/api.xpack.security.clear_cached_roles.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityClearCachedRolesFunc(t Transport) SecurityClearCachedRoles {
+	return func(name []string, o ...func(*SecurityClearCachedRolesRequest)) (*Response, error) {
+		var r = SecurityClearCachedRolesRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityClearCachedRoles - Evicts roles from the native role cache.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html.
+//
+type SecurityClearCachedRoles func(name []string, o ...func(*SecurityClearCachedRolesRequest)) (*Response, error)
+
+// SecurityClearCachedRolesRequest configures the Security Clear Cached Roles API request.
+//
+type SecurityClearCachedRolesRequest struct {
+	Name []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityClearCachedRolesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("role") + 1 + len(strings.Join(r.Name, ",")) + 1 + len("_clear_cache"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Name, ","))
+	path.WriteString("/")
+	path.WriteString("_clear_cache")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityClearCachedRoles) WithContext(v context.Context) func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityClearCachedRoles) WithPretty() func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityClearCachedRoles) WithHuman() func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityClearCachedRoles) WithErrorTrace() func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityClearCachedRoles) WithFilterPath(v ...string) func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityClearCachedRoles) WithHeader(h map[string]string) func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityClearCachedRoles) WithOpaqueID(s string) func(*SecurityClearCachedRolesRequest) {
+	return func(r *SecurityClearCachedRolesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.clear_cached_service_tokens.go b/esapi/api.xpack.security.clear_cached_service_tokens.go
new file mode 100644
index 0000000000..08ed4a5eac
--- /dev/null
+++ b/esapi/api.xpack.security.clear_cached_service_tokens.go
@@ -0,0 +1,215 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityClearCachedServiceTokensFunc(t Transport) SecurityClearCachedServiceTokens {
+	return func(name []string, namespace string, service string, o ...func(*SecurityClearCachedServiceTokensRequest)) (*Response, error) {
+		var r = SecurityClearCachedServiceTokensRequest{Name: name, Service: service, Namespace: namespace}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityClearCachedServiceTokens - Evicts tokens from the service account token caches.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-service-token-caches.html.
+//
+type SecurityClearCachedServiceTokens func(name []string, namespace string, service string, o ...func(*SecurityClearCachedServiceTokensRequest)) (*Response, error)
+
+// SecurityClearCachedServiceTokensRequest configures the Security Clear Cached Service Tokens API request.
+//
+type SecurityClearCachedServiceTokensRequest struct {
+	Name      []string
+	Namespace string
+	Service   string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityClearCachedServiceTokensRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("service") + 1 + len(r.Namespace) + 1 + len(r.Service) + 1 + len("credential") + 1 + len("token") + 1 + len(strings.Join(r.Name, ",")) + 1 + len("_clear_cache"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("service")
+	path.WriteString("/")
+	path.WriteString(r.Namespace)
+	path.WriteString("/")
+	path.WriteString(r.Service)
+	path.WriteString("/")
+	path.WriteString("credential")
+	path.WriteString("/")
+	path.WriteString("token")
+	path.WriteString("/")
+	path.WriteString(strings.Join(r.Name, ","))
+	path.WriteString("/")
+	path.WriteString("_clear_cache")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityClearCachedServiceTokens) WithContext(v context.Context) func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityClearCachedServiceTokens) WithPretty() func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityClearCachedServiceTokens) WithHuman() func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityClearCachedServiceTokens) WithErrorTrace() func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityClearCachedServiceTokens) WithFilterPath(v ...string) func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityClearCachedServiceTokens) WithHeader(h map[string]string) func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityClearCachedServiceTokens) WithOpaqueID(s string) func(*SecurityClearCachedServiceTokensRequest) {
+	return func(r *SecurityClearCachedServiceTokensRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.create_api_key.go b/esapi/api.xpack.security.create_api_key.go
new file mode 100644
index 0000000000..ecf72aa442
--- /dev/null
+++ b/esapi/api.xpack.security.create_api_key.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityCreateAPIKeyFunc(t Transport) SecurityCreateAPIKey {
+	return func(body io.Reader, o ...func(*SecurityCreateAPIKeyRequest)) (*Response, error) {
+		var r = SecurityCreateAPIKeyRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityCreateAPIKey - Creates an API key for access without requiring basic authentication.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html.
+//
+type SecurityCreateAPIKey func(body io.Reader, o ...func(*SecurityCreateAPIKeyRequest)) (*Response, error)
+
+// SecurityCreateAPIKeyRequest configures the Security CreateAPI Key API request.
+//
+type SecurityCreateAPIKeyRequest struct {
+	Body io.Reader
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityCreateAPIKeyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(len("/_security/api_key"))
+	path.WriteString("/_security/api_key")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityCreateAPIKey) WithContext(v context.Context) func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityCreateAPIKey) WithRefresh(v string) func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityCreateAPIKey) WithPretty() func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityCreateAPIKey) WithHuman() func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityCreateAPIKey) WithErrorTrace() func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityCreateAPIKey) WithFilterPath(v ...string) func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityCreateAPIKey) WithHeader(h map[string]string) func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityCreateAPIKey) WithOpaqueID(s string) func(*SecurityCreateAPIKeyRequest) {
+	return func(r *SecurityCreateAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.create_service_token.go b/esapi/api.xpack.security.create_service_token.go
new file mode 100644
index 0000000000..53b443674c
--- /dev/null
+++ b/esapi/api.xpack.security.create_service_token.go
@@ -0,0 +1,237 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityCreateServiceTokenFunc(t Transport) SecurityCreateServiceToken {
+	return func(namespace string, service string, o ...func(*SecurityCreateServiceTokenRequest)) (*Response, error) {
+		var r = SecurityCreateServiceTokenRequest{Service: service, Namespace: namespace}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityCreateServiceToken - Creates a service account token for access without requiring basic authentication.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-service-token.html.
+//
+type SecurityCreateServiceToken func(namespace string, service string, o ...func(*SecurityCreateServiceTokenRequest)) (*Response, error)
+
+// SecurityCreateServiceTokenRequest configures the Security Create Service Token API request.
+//
+type SecurityCreateServiceTokenRequest struct {
+	Name      string
+	Namespace string
+	Service   string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityCreateServiceTokenRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("service") + 1 + len(r.Namespace) + 1 + len(r.Service) + 1 + len("credential") + 1 + len("token") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("service")
+	path.WriteString("/")
+	path.WriteString(r.Namespace)
+	path.WriteString("/")
+	path.WriteString(r.Service)
+	path.WriteString("/")
+	path.WriteString("credential")
+	path.WriteString("/")
+	path.WriteString("token")
+	if r.Name != "" {
+		path.WriteString("/")
+		path.WriteString(r.Name)
+	}
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityCreateServiceToken) WithContext(v context.Context) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - an identifier for the token name.
+//
+func (f SecurityCreateServiceToken) WithName(v string) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.Name = v
+	}
+}
+
+// WithRefresh - if `true` then refresh the affected shards to make this operation visible to search, if `wait_for` (the default) then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityCreateServiceToken) WithRefresh(v string) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityCreateServiceToken) WithPretty() func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityCreateServiceToken) WithHuman() func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityCreateServiceToken) WithErrorTrace() func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityCreateServiceToken) WithFilterPath(v ...string) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityCreateServiceToken) WithHeader(h map[string]string) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityCreateServiceToken) WithOpaqueID(s string) func(*SecurityCreateServiceTokenRequest) {
+	return func(r *SecurityCreateServiceTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.delete_privileges.go b/esapi/api.xpack.security.delete_privileges.go
new file mode 100644
index 0000000000..1e98510625
--- /dev/null
+++ b/esapi/api.xpack.security.delete_privileges.go
@@ -0,0 +1,220 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDeletePrivilegesFunc(t Transport) SecurityDeletePrivileges {
+	return func(name string, application string, o ...func(*SecurityDeletePrivilegesRequest)) (*Response, error) {
+		var r = SecurityDeletePrivilegesRequest{Name: name, Application: application}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDeletePrivileges - Removes application privileges.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html.
+//
+type SecurityDeletePrivileges func(name string, application string, o ...func(*SecurityDeletePrivilegesRequest)) (*Response, error)
+
+// SecurityDeletePrivilegesRequest configures the Security Delete Privileges API request.
+//
+type SecurityDeletePrivilegesRequest struct {
+	Application string
+	Name        string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDeletePrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_security") + 1 + len("privilege") + 1 + len(r.Application) + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("privilege")
+	path.WriteString("/")
+	path.WriteString(r.Application)
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDeletePrivileges) WithContext(v context.Context) func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDeletePrivileges) WithRefresh(v string) func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDeletePrivileges) WithPretty() func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDeletePrivileges) WithHuman() func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDeletePrivileges) WithErrorTrace() func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDeletePrivileges) WithFilterPath(v ...string) func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDeletePrivileges) WithHeader(h map[string]string) func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDeletePrivileges) WithOpaqueID(s string) func(*SecurityDeletePrivilegesRequest) {
+	return func(r *SecurityDeletePrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.delete_role.go b/esapi/api.xpack.security.delete_role.go
new file mode 100644
index 0000000000..2b1dad629b
--- /dev/null
+++ b/esapi/api.xpack.security.delete_role.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDeleteRoleFunc(t Transport) SecurityDeleteRole {
+	return func(name string, o ...func(*SecurityDeleteRoleRequest)) (*Response, error) {
+		var r = SecurityDeleteRoleRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDeleteRole - Removes roles in the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-role.html.
+//
+type SecurityDeleteRole func(name string, o ...func(*SecurityDeleteRoleRequest)) (*Response, error)
+
+// SecurityDeleteRoleRequest configures the Security Delete Role API request.
+//
+type SecurityDeleteRoleRequest struct {
+	Name string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDeleteRoleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_security") + 1 + len("role") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDeleteRole) WithContext(v context.Context) func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDeleteRole) WithRefresh(v string) func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDeleteRole) WithPretty() func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDeleteRole) WithHuman() func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDeleteRole) WithErrorTrace() func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDeleteRole) WithFilterPath(v ...string) func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDeleteRole) WithHeader(h map[string]string) func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDeleteRole) WithOpaqueID(s string) func(*SecurityDeleteRoleRequest) {
+	return func(r *SecurityDeleteRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.delete_role_mapping.go b/esapi/api.xpack.security.delete_role_mapping.go
new file mode 100644
index 0000000000..de639aedf2
--- /dev/null
+++ b/esapi/api.xpack.security.delete_role_mapping.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDeleteRoleMappingFunc(t Transport) SecurityDeleteRoleMapping {
+	return func(name string, o ...func(*SecurityDeleteRoleMappingRequest)) (*Response, error) {
+		var r = SecurityDeleteRoleMappingRequest{Name: name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDeleteRoleMapping - Removes role mappings.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-role-mapping.html.
+//
+type SecurityDeleteRoleMapping func(name string, o ...func(*SecurityDeleteRoleMappingRequest)) (*Response, error)
+
+// SecurityDeleteRoleMappingRequest configures the Security Delete Role Mapping API request.
+//
+type SecurityDeleteRoleMappingRequest struct {
+	Name string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDeleteRoleMappingRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_security") + 1 + len("role_mapping") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role_mapping")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDeleteRoleMapping) WithContext(v context.Context) func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDeleteRoleMapping) WithRefresh(v string) func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDeleteRoleMapping) WithPretty() func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDeleteRoleMapping) WithHuman() func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDeleteRoleMapping) WithErrorTrace() func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDeleteRoleMapping) WithFilterPath(v ...string) func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDeleteRoleMapping) WithHeader(h map[string]string) func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDeleteRoleMapping) WithOpaqueID(s string) func(*SecurityDeleteRoleMappingRequest) {
+	return func(r *SecurityDeleteRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.delete_service_token.go b/esapi/api.xpack.security.delete_service_token.go
new file mode 100644
index 0000000000..74ece81e9a
--- /dev/null
+++ b/esapi/api.xpack.security.delete_service_token.go
@@ -0,0 +1,227 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDeleteServiceTokenFunc(t Transport) SecurityDeleteServiceToken {
+	return func(name string, namespace string, service string, o ...func(*SecurityDeleteServiceTokenRequest)) (*Response, error) {
+		var r = SecurityDeleteServiceTokenRequest{Name: name, Namespace: namespace, Service: service}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDeleteServiceToken - Deletes a service account token.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-service-token.html.
+//
+type SecurityDeleteServiceToken func(name string, service string, namespace string, o ...func(*SecurityDeleteServiceTokenRequest)) (*Response, error)
+
+// SecurityDeleteServiceTokenRequest configures the Security Delete Service Token API request.
+//
+type SecurityDeleteServiceTokenRequest struct {
+	Name      string
+	Namespace string
+	Service   string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDeleteServiceTokenRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_security") + 1 + len("service") + 1 + len(r.Namespace) + 1 + len(r.Service) + 1 + len("credential") + 1 + len("token") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("service")
+	path.WriteString("/")
+	path.WriteString(r.Namespace)
+	path.WriteString("/")
+	path.WriteString(r.Service)
+	path.WriteString("/")
+	path.WriteString("credential")
+	path.WriteString("/")
+	path.WriteString("token")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDeleteServiceToken) WithContext(v context.Context) func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` then refresh the affected shards to make this operation visible to search, if `wait_for` (the default) then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDeleteServiceToken) WithRefresh(v string) func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDeleteServiceToken) WithPretty() func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDeleteServiceToken) WithHuman() func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDeleteServiceToken) WithErrorTrace() func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDeleteServiceToken) WithFilterPath(v ...string) func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDeleteServiceToken) WithHeader(h map[string]string) func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDeleteServiceToken) WithOpaqueID(s string) func(*SecurityDeleteServiceTokenRequest) {
+	return func(r *SecurityDeleteServiceTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.delete_user.go b/esapi/api.xpack.security.delete_user.go
new file mode 100644
index 0000000000..9486d42815
--- /dev/null
+++ b/esapi/api.xpack.security.delete_user.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDeleteUserFunc(t Transport) SecurityDeleteUser {
+	return func(username string, o ...func(*SecurityDeleteUserRequest)) (*Response, error) {
+		var r = SecurityDeleteUserRequest{Username: username}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDeleteUser - Deletes users from the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-user.html.
+//
+type SecurityDeleteUser func(username string, o ...func(*SecurityDeleteUserRequest)) (*Response, error)
+
+// SecurityDeleteUserRequest configures the Security Delete User API request.
+//
+type SecurityDeleteUserRequest struct {
+	Username string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDeleteUserRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.Username))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	path.WriteString("/")
+	path.WriteString(r.Username)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDeleteUser) WithContext(v context.Context) func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDeleteUser) WithRefresh(v string) func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDeleteUser) WithPretty() func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDeleteUser) WithHuman() func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDeleteUser) WithErrorTrace() func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDeleteUser) WithFilterPath(v ...string) func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDeleteUser) WithHeader(h map[string]string) func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDeleteUser) WithOpaqueID(s string) func(*SecurityDeleteUserRequest) {
+	return func(r *SecurityDeleteUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.disable_user.go b/esapi/api.xpack.security.disable_user.go
new file mode 100644
index 0000000000..4e26907e89
--- /dev/null
+++ b/esapi/api.xpack.security.disable_user.go
@@ -0,0 +1,219 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityDisableUserFunc(t Transport) SecurityDisableUser {
+	return func(username string, o ...func(*SecurityDisableUserRequest)) (*Response, error) {
+		var r = SecurityDisableUserRequest{Username: username}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityDisableUser - Disables users in the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-disable-user.html.
+//
+type SecurityDisableUser func(username string, o ...func(*SecurityDisableUserRequest)) (*Response, error)
+
+// SecurityDisableUserRequest configures the Security Disable User API request.
+//
+type SecurityDisableUserRequest struct {
+	Username string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityDisableUserRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.Username) + 1 + len("_disable"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	path.WriteString("/")
+	path.WriteString(r.Username)
+	path.WriteString("/")
+	path.WriteString("_disable")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityDisableUser) WithContext(v context.Context) func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityDisableUser) WithRefresh(v string) func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityDisableUser) WithPretty() func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityDisableUser) WithHuman() func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityDisableUser) WithErrorTrace() func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityDisableUser) WithFilterPath(v ...string) func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityDisableUser) WithHeader(h map[string]string) func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityDisableUser) WithOpaqueID(s string) func(*SecurityDisableUserRequest) {
+	return func(r *SecurityDisableUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.enable_user.go b/esapi/api.xpack.security.enable_user.go
new file mode 100644
index 0000000000..0d9826e4aa
--- /dev/null
+++ b/esapi/api.xpack.security.enable_user.go
@@ -0,0 +1,219 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityEnableUserFunc(t Transport) SecurityEnableUser {
+	return func(username string, o ...func(*SecurityEnableUserRequest)) (*Response, error) {
+		var r = SecurityEnableUserRequest{Username: username}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityEnableUser - Enables users in the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-enable-user.html.
+//
+type SecurityEnableUser func(username string, o ...func(*SecurityEnableUserRequest)) (*Response, error)
+
+// SecurityEnableUserRequest configures the Security Enable User API request.
+//
+type SecurityEnableUserRequest struct {
+	Username string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityEnableUserRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.Username) + 1 + len("_enable"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	path.WriteString("/")
+	path.WriteString(r.Username)
+	path.WriteString("/")
+	path.WriteString("_enable")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityEnableUser) WithContext(v context.Context) func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityEnableUser) WithRefresh(v string) func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityEnableUser) WithPretty() func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityEnableUser) WithHuman() func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityEnableUser) WithErrorTrace() func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityEnableUser) WithFilterPath(v ...string) func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityEnableUser) WithHeader(h map[string]string) func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityEnableUser) WithOpaqueID(s string) func(*SecurityEnableUserRequest) {
+	return func(r *SecurityEnableUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_api_key.go b/esapi/api.xpack.security.get_api_key.go
new file mode 100644
index 0000000000..4c52c37368
--- /dev/null
+++ b/esapi/api.xpack.security.get_api_key.go
@@ -0,0 +1,263 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newSecurityGetAPIKeyFunc(t Transport) SecurityGetAPIKey {
+	return func(o ...func(*SecurityGetAPIKeyRequest)) (*Response, error) {
+		var r = SecurityGetAPIKeyRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetAPIKey - Retrieves information for one or more API keys.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html.
+//
+type SecurityGetAPIKey func(o ...func(*SecurityGetAPIKeyRequest)) (*Response, error)
+
+// SecurityGetAPIKeyRequest configures the Security GetAPI Key API request.
+//
+type SecurityGetAPIKeyRequest struct {
+	ID        string
+	Name      string
+	Owner     *bool
+	RealmName string
+	Username  string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetAPIKeyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_security/api_key"))
+	path.WriteString("/_security/api_key")
+
+	params = make(map[string]string)
+
+	if r.ID != "" {
+		params["id"] = r.ID
+	}
+
+	if r.Name != "" {
+		params["name"] = r.Name
+	}
+
+	if r.Owner != nil {
+		params["owner"] = strconv.FormatBool(*r.Owner)
+	}
+
+	if r.RealmName != "" {
+		params["realm_name"] = r.RealmName
+	}
+
+	if r.Username != "" {
+		params["username"] = r.Username
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetAPIKey) WithContext(v context.Context) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithID - api key ID of the api key to be retrieved.
+//
+func (f SecurityGetAPIKey) WithID(v string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.ID = v
+	}
+}
+
+// WithName - api key name of the api key to be retrieved.
+//
+func (f SecurityGetAPIKey) WithName(v string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.Name = v
+	}
+}
+
+// WithOwner - flag to query api keys owned by the currently authenticated user.
+//
+func (f SecurityGetAPIKey) WithOwner(v bool) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.Owner = &v
+	}
+}
+
+// WithRealmName - realm name of the user who created this api key to be retrieved.
+//
+func (f SecurityGetAPIKey) WithRealmName(v string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.RealmName = v
+	}
+}
+
+// WithUsername - user name of the user who created this api key to be retrieved.
+//
+func (f SecurityGetAPIKey) WithUsername(v string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.Username = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetAPIKey) WithPretty() func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetAPIKey) WithHuman() func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetAPIKey) WithErrorTrace() func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetAPIKey) WithFilterPath(v ...string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetAPIKey) WithHeader(h map[string]string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetAPIKey) WithOpaqueID(s string) func(*SecurityGetAPIKeyRequest) {
+	return func(r *SecurityGetAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_builtin_privileges.go b/esapi/api.xpack.security.get_builtin_privileges.go
new file mode 100644
index 0000000000..edfdfd4f3a
--- /dev/null
+++ b/esapi/api.xpack.security.get_builtin_privileges.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetBuiltinPrivilegesFunc(t Transport) SecurityGetBuiltinPrivileges {
+	return func(o ...func(*SecurityGetBuiltinPrivilegesRequest)) (*Response, error) {
+		var r = SecurityGetBuiltinPrivilegesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetBuiltinPrivileges - Retrieves the list of cluster privileges and index privileges that are available in this version of Elasticsearch.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-builtin-privileges.html.
+//
+type SecurityGetBuiltinPrivileges func(o ...func(*SecurityGetBuiltinPrivilegesRequest)) (*Response, error)
+
+// SecurityGetBuiltinPrivilegesRequest configures the Security Get Builtin Privileges API request.
+//
+type SecurityGetBuiltinPrivilegesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetBuiltinPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_security/privilege/_builtin"))
+	path.WriteString("/_security/privilege/_builtin")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetBuiltinPrivileges) WithContext(v context.Context) func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetBuiltinPrivileges) WithPretty() func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetBuiltinPrivileges) WithHuman() func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetBuiltinPrivileges) WithErrorTrace() func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetBuiltinPrivileges) WithFilterPath(v ...string) func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetBuiltinPrivileges) WithHeader(h map[string]string) func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetBuiltinPrivileges) WithOpaqueID(s string) func(*SecurityGetBuiltinPrivilegesRequest) {
+	return func(r *SecurityGetBuiltinPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_privileges.go b/esapi/api.xpack.security.get_privileges.go
new file mode 100644
index 0000000000..3662f2180d
--- /dev/null
+++ b/esapi/api.xpack.security.get_privileges.go
@@ -0,0 +1,226 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetPrivilegesFunc(t Transport) SecurityGetPrivileges {
+	return func(o ...func(*SecurityGetPrivilegesRequest)) (*Response, error) {
+		var r = SecurityGetPrivilegesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetPrivileges - Retrieves application privileges.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-privileges.html.
+//
+type SecurityGetPrivileges func(o ...func(*SecurityGetPrivilegesRequest)) (*Response, error)
+
+// SecurityGetPrivilegesRequest configures the Security Get Privileges API request.
+//
+type SecurityGetPrivilegesRequest struct {
+	Application string
+	Name        string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("privilege") + 1 + len(r.Application) + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("privilege")
+	if r.Application != "" {
+		path.WriteString("/")
+		path.WriteString(r.Application)
+	}
+	if r.Name != "" {
+		path.WriteString("/")
+		path.WriteString(r.Name)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetPrivileges) WithContext(v context.Context) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithApplication - application name.
+//
+func (f SecurityGetPrivileges) WithApplication(v string) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.Application = v
+	}
+}
+
+// WithName - privilege name.
+//
+func (f SecurityGetPrivileges) WithName(v string) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetPrivileges) WithPretty() func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetPrivileges) WithHuman() func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetPrivileges) WithErrorTrace() func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetPrivileges) WithFilterPath(v ...string) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetPrivileges) WithHeader(h map[string]string) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetPrivileges) WithOpaqueID(s string) func(*SecurityGetPrivilegesRequest) {
+	return func(r *SecurityGetPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_role.go b/esapi/api.xpack.security.get_role.go
new file mode 100644
index 0000000000..176a1f1762
--- /dev/null
+++ b/esapi/api.xpack.security.get_role.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetRoleFunc(t Transport) SecurityGetRole {
+	return func(o ...func(*SecurityGetRoleRequest)) (*Response, error) {
+		var r = SecurityGetRoleRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetRole - Retrieves roles in the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role.html.
+//
+type SecurityGetRole func(o ...func(*SecurityGetRoleRequest)) (*Response, error)
+
+// SecurityGetRoleRequest configures the Security Get Role API request.
+//
+type SecurityGetRoleRequest struct {
+	Name []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetRoleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("role") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetRole) WithContext(v context.Context) func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a list of role names.
+//
+func (f SecurityGetRole) WithName(v ...string) func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetRole) WithPretty() func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetRole) WithHuman() func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetRole) WithErrorTrace() func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetRole) WithFilterPath(v ...string) func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetRole) WithHeader(h map[string]string) func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetRole) WithOpaqueID(s string) func(*SecurityGetRoleRequest) {
+	return func(r *SecurityGetRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_role_mapping.go b/esapi/api.xpack.security.get_role_mapping.go
new file mode 100644
index 0000000000..0cf7f5fc49
--- /dev/null
+++ b/esapi/api.xpack.security.get_role_mapping.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetRoleMappingFunc(t Transport) SecurityGetRoleMapping {
+	return func(o ...func(*SecurityGetRoleMappingRequest)) (*Response, error) {
+		var r = SecurityGetRoleMappingRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetRoleMapping - Retrieves role mappings.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role-mapping.html.
+//
+type SecurityGetRoleMapping func(o ...func(*SecurityGetRoleMappingRequest)) (*Response, error)
+
+// SecurityGetRoleMappingRequest configures the Security Get Role Mapping API request.
+//
+type SecurityGetRoleMappingRequest struct {
+	Name []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetRoleMappingRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("role_mapping") + 1 + len(strings.Join(r.Name, ",")))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role_mapping")
+	if len(r.Name) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Name, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetRoleMapping) WithContext(v context.Context) func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.ctx = v
+	}
+}
+
+// WithName - a list of role-mapping names.
+//
+func (f SecurityGetRoleMapping) WithName(v ...string) func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.Name = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetRoleMapping) WithPretty() func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetRoleMapping) WithHuman() func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetRoleMapping) WithErrorTrace() func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetRoleMapping) WithFilterPath(v ...string) func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetRoleMapping) WithHeader(h map[string]string) func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetRoleMapping) WithOpaqueID(s string) func(*SecurityGetRoleMappingRequest) {
+	return func(r *SecurityGetRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_service_accounts.go b/esapi/api.xpack.security.get_service_accounts.go
new file mode 100644
index 0000000000..b03c930798
--- /dev/null
+++ b/esapi/api.xpack.security.get_service_accounts.go
@@ -0,0 +1,226 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetServiceAccountsFunc(t Transport) SecurityGetServiceAccounts {
+	return func(o ...func(*SecurityGetServiceAccountsRequest)) (*Response, error) {
+		var r = SecurityGetServiceAccountsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetServiceAccounts - Retrieves information about service accounts.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-service-accounts.html.
+//
+type SecurityGetServiceAccounts func(o ...func(*SecurityGetServiceAccountsRequest)) (*Response, error)
+
+// SecurityGetServiceAccountsRequest configures the Security Get Service Accounts API request.
+//
+type SecurityGetServiceAccountsRequest struct {
+	Namespace string
+	Service   string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetServiceAccountsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("service") + 1 + len(r.Namespace) + 1 + len(r.Service))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("service")
+	if r.Namespace != "" {
+		path.WriteString("/")
+		path.WriteString(r.Namespace)
+	}
+	if r.Service != "" {
+		path.WriteString("/")
+		path.WriteString(r.Service)
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetServiceAccounts) WithContext(v context.Context) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithNamespace - an identifier for the namespace.
+//
+func (f SecurityGetServiceAccounts) WithNamespace(v string) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.Namespace = v
+	}
+}
+
+// WithService - an identifier for the service name.
+//
+func (f SecurityGetServiceAccounts) WithService(v string) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.Service = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetServiceAccounts) WithPretty() func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetServiceAccounts) WithHuman() func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetServiceAccounts) WithErrorTrace() func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetServiceAccounts) WithFilterPath(v ...string) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetServiceAccounts) WithHeader(h map[string]string) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetServiceAccounts) WithOpaqueID(s string) func(*SecurityGetServiceAccountsRequest) {
+	return func(r *SecurityGetServiceAccountsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_service_credentials.go b/esapi/api.xpack.security.get_service_credentials.go
new file mode 100644
index 0000000000..ca1abc9b67
--- /dev/null
+++ b/esapi/api.xpack.security.get_service_credentials.go
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetServiceCredentialsFunc(t Transport) SecurityGetServiceCredentials {
+	return func(namespace string, service string, o ...func(*SecurityGetServiceCredentialsRequest)) (*Response, error) {
+		var r = SecurityGetServiceCredentialsRequest{Namespace: namespace, Service: service}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetServiceCredentials - Retrieves information of all service credentials for a service account.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-service-credentials.html.
+//
+type SecurityGetServiceCredentials func(namespace string, service string, o ...func(*SecurityGetServiceCredentialsRequest)) (*Response, error)
+
+// SecurityGetServiceCredentialsRequest configures the Security Get Service Credentials API request.
+//
+type SecurityGetServiceCredentialsRequest struct {
+	Namespace string
+	Service   string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetServiceCredentialsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("service") + 1 + len(r.Namespace) + 1 + len(r.Service) + 1 + len("credential"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("service")
+	path.WriteString("/")
+	path.WriteString(r.Namespace)
+	path.WriteString("/")
+	path.WriteString(r.Service)
+	path.WriteString("/")
+	path.WriteString("credential")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetServiceCredentials) WithContext(v context.Context) func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetServiceCredentials) WithPretty() func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetServiceCredentials) WithHuman() func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetServiceCredentials) WithErrorTrace() func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetServiceCredentials) WithFilterPath(v ...string) func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetServiceCredentials) WithHeader(h map[string]string) func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetServiceCredentials) WithOpaqueID(s string) func(*SecurityGetServiceCredentialsRequest) {
+	return func(r *SecurityGetServiceCredentialsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_token.go b/esapi/api.xpack.security.get_token.go
new file mode 100644
index 0000000000..8db1ec0fab
--- /dev/null
+++ b/esapi/api.xpack.security.get_token.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetTokenFunc(t Transport) SecurityGetToken {
+	return func(body io.Reader, o ...func(*SecurityGetTokenRequest)) (*Response, error) {
+		var r = SecurityGetTokenRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetToken - Creates a bearer token for access without requiring basic authentication.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-token.html.
+//
+type SecurityGetToken func(body io.Reader, o ...func(*SecurityGetTokenRequest)) (*Response, error)
+
+// SecurityGetTokenRequest configures the Security Get Token API request.
+//
+type SecurityGetTokenRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetTokenRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/oauth2/token"))
+	path.WriteString("/_security/oauth2/token")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetToken) WithContext(v context.Context) func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetToken) WithPretty() func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetToken) WithHuman() func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetToken) WithErrorTrace() func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetToken) WithFilterPath(v ...string) func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetToken) WithHeader(h map[string]string) func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetToken) WithOpaqueID(s string) func(*SecurityGetTokenRequest) {
+	return func(r *SecurityGetTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_user.go b/esapi/api.xpack.security.get_user.go
new file mode 100644
index 0000000000..d4fb6c3e83
--- /dev/null
+++ b/esapi/api.xpack.security.get_user.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetUserFunc(t Transport) SecurityGetUser {
+	return func(o ...func(*SecurityGetUserRequest)) (*Response, error) {
+		var r = SecurityGetUserRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetUser - Retrieves information about users in the native realm and built-in users.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user.html.
+//
+type SecurityGetUser func(o ...func(*SecurityGetUserRequest)) (*Response, error)
+
+// SecurityGetUserRequest configures the Security Get User API request.
+//
+type SecurityGetUserRequest struct {
+	Username []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetUserRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(strings.Join(r.Username, ",")))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	if len(r.Username) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Username, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetUser) WithContext(v context.Context) func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.ctx = v
+	}
+}
+
+// WithUsername - a list of usernames.
+//
+func (f SecurityGetUser) WithUsername(v ...string) func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.Username = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetUser) WithPretty() func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetUser) WithHuman() func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetUser) WithErrorTrace() func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetUser) WithFilterPath(v ...string) func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetUser) WithHeader(h map[string]string) func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetUser) WithOpaqueID(s string) func(*SecurityGetUserRequest) {
+	return func(r *SecurityGetUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.get_user_privileges.go b/esapi/api.xpack.security.get_user_privileges.go
new file mode 100644
index 0000000000..8c2fbc6583
--- /dev/null
+++ b/esapi/api.xpack.security.get_user_privileges.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGetUserPrivilegesFunc(t Transport) SecurityGetUserPrivileges {
+	return func(o ...func(*SecurityGetUserPrivilegesRequest)) (*Response, error) {
+		var r = SecurityGetUserPrivilegesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGetUserPrivileges - Retrieves security privileges for the logged in user.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user-privileges.html.
+//
+type SecurityGetUserPrivileges func(o ...func(*SecurityGetUserPrivilegesRequest)) (*Response, error)
+
+// SecurityGetUserPrivilegesRequest configures the Security Get User Privileges API request.
+//
+type SecurityGetUserPrivilegesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGetUserPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_security/user/_privileges"))
+	path.WriteString("/_security/user/_privileges")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGetUserPrivileges) WithContext(v context.Context) func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGetUserPrivileges) WithPretty() func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGetUserPrivileges) WithHuman() func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGetUserPrivileges) WithErrorTrace() func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGetUserPrivileges) WithFilterPath(v ...string) func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGetUserPrivileges) WithHeader(h map[string]string) func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGetUserPrivileges) WithOpaqueID(s string) func(*SecurityGetUserPrivilegesRequest) {
+	return func(r *SecurityGetUserPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.grant_api_key.go b/esapi/api.xpack.security.grant_api_key.go
new file mode 100644
index 0000000000..f99e623a64
--- /dev/null
+++ b/esapi/api.xpack.security.grant_api_key.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityGrantAPIKeyFunc(t Transport) SecurityGrantAPIKey {
+	return func(body io.Reader, o ...func(*SecurityGrantAPIKeyRequest)) (*Response, error) {
+		var r = SecurityGrantAPIKeyRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityGrantAPIKey - Creates an API key on behalf of another user.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-grant-api-key.html.
+//
+type SecurityGrantAPIKey func(body io.Reader, o ...func(*SecurityGrantAPIKeyRequest)) (*Response, error)
+
+// SecurityGrantAPIKeyRequest configures the Security GrantAPI Key API request.
+//
+type SecurityGrantAPIKeyRequest struct {
+	Body io.Reader
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityGrantAPIKeyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/api_key/grant"))
+	path.WriteString("/_security/api_key/grant")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityGrantAPIKey) WithContext(v context.Context) func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityGrantAPIKey) WithRefresh(v string) func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityGrantAPIKey) WithPretty() func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityGrantAPIKey) WithHuman() func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityGrantAPIKey) WithErrorTrace() func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityGrantAPIKey) WithFilterPath(v ...string) func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityGrantAPIKey) WithHeader(h map[string]string) func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityGrantAPIKey) WithOpaqueID(s string) func(*SecurityGrantAPIKeyRequest) {
+	return func(r *SecurityGrantAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.has_privileges.go b/esapi/api.xpack.security.has_privileges.go
new file mode 100644
index 0000000000..7f707de1cc
--- /dev/null
+++ b/esapi/api.xpack.security.has_privileges.go
@@ -0,0 +1,222 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityHasPrivilegesFunc(t Transport) SecurityHasPrivileges {
+	return func(body io.Reader, o ...func(*SecurityHasPrivilegesRequest)) (*Response, error) {
+		var r = SecurityHasPrivilegesRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityHasPrivileges - Determines whether the specified user has a specified list of privileges.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-has-privileges.html.
+//
+type SecurityHasPrivileges func(body io.Reader, o ...func(*SecurityHasPrivilegesRequest)) (*Response, error)
+
+// SecurityHasPrivilegesRequest configures the Security Has Privileges API request.
+//
+type SecurityHasPrivilegesRequest struct {
+	Body io.Reader
+
+	User string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityHasPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.User) + 1 + len("_has_privileges"))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	if r.User != "" {
+		path.WriteString("/")
+		path.WriteString(r.User)
+	}
+	path.WriteString("/")
+	path.WriteString("_has_privileges")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityHasPrivileges) WithContext(v context.Context) func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithUser - username.
+//
+func (f SecurityHasPrivileges) WithUser(v string) func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.User = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityHasPrivileges) WithPretty() func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityHasPrivileges) WithHuman() func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityHasPrivileges) WithErrorTrace() func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityHasPrivileges) WithFilterPath(v ...string) func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityHasPrivileges) WithHeader(h map[string]string) func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityHasPrivileges) WithOpaqueID(s string) func(*SecurityHasPrivilegesRequest) {
+	return func(r *SecurityHasPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.invalidate_api_key.go b/esapi/api.xpack.security.invalidate_api_key.go
new file mode 100644
index 0000000000..bc4770aab4
--- /dev/null
+++ b/esapi/api.xpack.security.invalidate_api_key.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityInvalidateAPIKeyFunc(t Transport) SecurityInvalidateAPIKey {
+	return func(body io.Reader, o ...func(*SecurityInvalidateAPIKeyRequest)) (*Response, error) {
+		var r = SecurityInvalidateAPIKeyRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityInvalidateAPIKey - Invalidates one or more API keys.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html.
+//
+type SecurityInvalidateAPIKey func(body io.Reader, o ...func(*SecurityInvalidateAPIKeyRequest)) (*Response, error)
+
+// SecurityInvalidateAPIKeyRequest configures the Security InvalidateAPI Key API request.
+//
+type SecurityInvalidateAPIKeyRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityInvalidateAPIKeyRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(len("/_security/api_key"))
+	path.WriteString("/_security/api_key")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityInvalidateAPIKey) WithContext(v context.Context) func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityInvalidateAPIKey) WithPretty() func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityInvalidateAPIKey) WithHuman() func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityInvalidateAPIKey) WithErrorTrace() func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityInvalidateAPIKey) WithFilterPath(v ...string) func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityInvalidateAPIKey) WithHeader(h map[string]string) func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityInvalidateAPIKey) WithOpaqueID(s string) func(*SecurityInvalidateAPIKeyRequest) {
+	return func(r *SecurityInvalidateAPIKeyRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.invalidate_token.go b/esapi/api.xpack.security.invalidate_token.go
new file mode 100644
index 0000000000..65e041e287
--- /dev/null
+++ b/esapi/api.xpack.security.invalidate_token.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityInvalidateTokenFunc(t Transport) SecurityInvalidateToken {
+	return func(body io.Reader, o ...func(*SecurityInvalidateTokenRequest)) (*Response, error) {
+		var r = SecurityInvalidateTokenRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityInvalidateToken - Invalidates one or more access tokens or refresh tokens.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-token.html.
+//
+type SecurityInvalidateToken func(body io.Reader, o ...func(*SecurityInvalidateTokenRequest)) (*Response, error)
+
+// SecurityInvalidateTokenRequest configures the Security Invalidate Token API request.
+//
+type SecurityInvalidateTokenRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityInvalidateTokenRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(len("/_security/oauth2/token"))
+	path.WriteString("/_security/oauth2/token")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityInvalidateToken) WithContext(v context.Context) func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityInvalidateToken) WithPretty() func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityInvalidateToken) WithHuman() func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityInvalidateToken) WithErrorTrace() func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityInvalidateToken) WithFilterPath(v ...string) func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityInvalidateToken) WithHeader(h map[string]string) func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityInvalidateToken) WithOpaqueID(s string) func(*SecurityInvalidateTokenRequest) {
+	return func(r *SecurityInvalidateTokenRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.put_privileges.go b/esapi/api.xpack.security.put_privileges.go
new file mode 100644
index 0000000000..e56d174ed5
--- /dev/null
+++ b/esapi/api.xpack.security.put_privileges.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityPutPrivilegesFunc(t Transport) SecurityPutPrivileges {
+	return func(body io.Reader, o ...func(*SecurityPutPrivilegesRequest)) (*Response, error) {
+		var r = SecurityPutPrivilegesRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityPutPrivileges - Adds or updates application privileges.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-privileges.html.
+//
+type SecurityPutPrivileges func(body io.Reader, o ...func(*SecurityPutPrivilegesRequest)) (*Response, error)
+
+// SecurityPutPrivilegesRequest configures the Security Put Privileges API request.
+//
+type SecurityPutPrivilegesRequest struct {
+	Body io.Reader
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityPutPrivilegesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(len("/_security/privilege/"))
+	path.WriteString("/_security/privilege/")
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityPutPrivileges) WithContext(v context.Context) func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityPutPrivileges) WithRefresh(v string) func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityPutPrivileges) WithPretty() func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityPutPrivileges) WithHuman() func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityPutPrivileges) WithErrorTrace() func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityPutPrivileges) WithFilterPath(v ...string) func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityPutPrivileges) WithHeader(h map[string]string) func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityPutPrivileges) WithOpaqueID(s string) func(*SecurityPutPrivilegesRequest) {
+	return func(r *SecurityPutPrivilegesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.put_role.go b/esapi/api.xpack.security.put_role.go
new file mode 100644
index 0000000000..023f2fd2a3
--- /dev/null
+++ b/esapi/api.xpack.security.put_role.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityPutRoleFunc(t Transport) SecurityPutRole {
+	return func(name string, body io.Reader, o ...func(*SecurityPutRoleRequest)) (*Response, error) {
+		var r = SecurityPutRoleRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityPutRole - Adds and updates roles in the native realm.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-role.html.
+//
+type SecurityPutRole func(name string, body io.Reader, o ...func(*SecurityPutRoleRequest)) (*Response, error)
+
+// SecurityPutRoleRequest configures the Security Put Role API request.
+//
+type SecurityPutRoleRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityPutRoleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("role") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityPutRole) WithContext(v context.Context) func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityPutRole) WithRefresh(v string) func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityPutRole) WithPretty() func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityPutRole) WithHuman() func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityPutRole) WithErrorTrace() func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityPutRole) WithFilterPath(v ...string) func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityPutRole) WithHeader(h map[string]string) func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityPutRole) WithOpaqueID(s string) func(*SecurityPutRoleRequest) {
+	return func(r *SecurityPutRoleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.put_role_mapping.go b/esapi/api.xpack.security.put_role_mapping.go
new file mode 100644
index 0000000000..9b6e030f3b
--- /dev/null
+++ b/esapi/api.xpack.security.put_role_mapping.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityPutRoleMappingFunc(t Transport) SecurityPutRoleMapping {
+	return func(name string, body io.Reader, o ...func(*SecurityPutRoleMappingRequest)) (*Response, error) {
+		var r = SecurityPutRoleMappingRequest{Name: name, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityPutRoleMapping - Creates and updates role mappings.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-role-mapping.html.
+//
+type SecurityPutRoleMapping func(name string, body io.Reader, o ...func(*SecurityPutRoleMappingRequest)) (*Response, error)
+
+// SecurityPutRoleMappingRequest configures the Security Put Role Mapping API request.
+//
+type SecurityPutRoleMappingRequest struct {
+	Body io.Reader
+
+	Name string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityPutRoleMappingRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("role_mapping") + 1 + len(r.Name))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("role_mapping")
+	path.WriteString("/")
+	path.WriteString(r.Name)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityPutRoleMapping) WithContext(v context.Context) func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityPutRoleMapping) WithRefresh(v string) func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityPutRoleMapping) WithPretty() func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityPutRoleMapping) WithHuman() func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityPutRoleMapping) WithErrorTrace() func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityPutRoleMapping) WithFilterPath(v ...string) func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityPutRoleMapping) WithHeader(h map[string]string) func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityPutRoleMapping) WithOpaqueID(s string) func(*SecurityPutRoleMappingRequest) {
+	return func(r *SecurityPutRoleMappingRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.put_user.go b/esapi/api.xpack.security.put_user.go
new file mode 100644
index 0000000000..4efa17221b
--- /dev/null
+++ b/esapi/api.xpack.security.put_user.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityPutUserFunc(t Transport) SecurityPutUser {
+	return func(username string, body io.Reader, o ...func(*SecurityPutUserRequest)) (*Response, error) {
+		var r = SecurityPutUserRequest{Username: username, Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityPutUser - Adds and updates users in the native realm. These users are commonly referred to as native users.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-user.html.
+//
+type SecurityPutUser func(username string, body io.Reader, o ...func(*SecurityPutUserRequest)) (*Response, error)
+
+// SecurityPutUserRequest configures the Security Put User API request.
+//
+type SecurityPutUserRequest struct {
+	Body io.Reader
+
+	Username string
+
+	Refresh string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityPutUserRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_security") + 1 + len("user") + 1 + len(r.Username))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("user")
+	path.WriteString("/")
+	path.WriteString(r.Username)
+
+	params = make(map[string]string)
+
+	if r.Refresh != "" {
+		params["refresh"] = r.Refresh
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityPutUser) WithContext(v context.Context) func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.ctx = v
+	}
+}
+
+// WithRefresh - if `true` (the default) then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` then do nothing with refreshes..
+//
+func (f SecurityPutUser) WithRefresh(v string) func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.Refresh = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityPutUser) WithPretty() func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityPutUser) WithHuman() func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityPutUser) WithErrorTrace() func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityPutUser) WithFilterPath(v ...string) func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityPutUser) WithHeader(h map[string]string) func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityPutUser) WithOpaqueID(s string) func(*SecurityPutUserRequest) {
+	return func(r *SecurityPutUserRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.query_api_keys.go b/esapi/api.xpack.security.query_api_keys.go
new file mode 100644
index 0000000000..09369bd269
--- /dev/null
+++ b/esapi/api.xpack.security.query_api_keys.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecurityQueryAPIKeysFunc(t Transport) SecurityQueryAPIKeys {
+	return func(o ...func(*SecurityQueryAPIKeysRequest)) (*Response, error) {
+		var r = SecurityQueryAPIKeysRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecurityQueryAPIKeys - Retrieves information for API keys using a subset of query DSL
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-query-api-key.html.
+//
+type SecurityQueryAPIKeys func(o ...func(*SecurityQueryAPIKeysRequest)) (*Response, error)
+
+// SecurityQueryAPIKeysRequest configures the Security QueryAPI Keys API request.
+//
+type SecurityQueryAPIKeysRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecurityQueryAPIKeysRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/_query/api_key"))
+	path.WriteString("/_security/_query/api_key")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecurityQueryAPIKeys) WithContext(v context.Context) func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - From, size, query, sort and search_after.
+//
+func (f SecurityQueryAPIKeys) WithBody(v io.Reader) func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecurityQueryAPIKeys) WithPretty() func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecurityQueryAPIKeys) WithHuman() func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecurityQueryAPIKeys) WithErrorTrace() func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecurityQueryAPIKeys) WithFilterPath(v ...string) func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecurityQueryAPIKeys) WithHeader(h map[string]string) func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecurityQueryAPIKeys) WithOpaqueID(s string) func(*SecurityQueryAPIKeysRequest) {
+	return func(r *SecurityQueryAPIKeysRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_authenticate.go b/esapi/api.xpack.security.saml_authenticate.go
new file mode 100644
index 0000000000..d6d26eabca
--- /dev/null
+++ b/esapi/api.xpack.security.saml_authenticate.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlAuthenticateFunc(t Transport) SecuritySamlAuthenticate {
+	return func(body io.Reader, o ...func(*SecuritySamlAuthenticateRequest)) (*Response, error) {
+		var r = SecuritySamlAuthenticateRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlAuthenticate - Exchanges a SAML Response message for an Elasticsearch access token and refresh token pair
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-authenticate.html.
+//
+type SecuritySamlAuthenticate func(body io.Reader, o ...func(*SecuritySamlAuthenticateRequest)) (*Response, error)
+
+// SecuritySamlAuthenticateRequest configures the Security Saml Authenticate API request.
+//
+type SecuritySamlAuthenticateRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlAuthenticateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/saml/authenticate"))
+	path.WriteString("/_security/saml/authenticate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlAuthenticate) WithContext(v context.Context) func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlAuthenticate) WithPretty() func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlAuthenticate) WithHuman() func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlAuthenticate) WithErrorTrace() func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlAuthenticate) WithFilterPath(v ...string) func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlAuthenticate) WithHeader(h map[string]string) func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlAuthenticate) WithOpaqueID(s string) func(*SecuritySamlAuthenticateRequest) {
+	return func(r *SecuritySamlAuthenticateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_complete_logout.go b/esapi/api.xpack.security.saml_complete_logout.go
new file mode 100644
index 0000000000..849b41b017
--- /dev/null
+++ b/esapi/api.xpack.security.saml_complete_logout.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlCompleteLogoutFunc(t Transport) SecuritySamlCompleteLogout {
+	return func(body io.Reader, o ...func(*SecuritySamlCompleteLogoutRequest)) (*Response, error) {
+		var r = SecuritySamlCompleteLogoutRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlCompleteLogout - Verifies the logout response sent from the SAML IdP
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-complete-logout.html.
+//
+type SecuritySamlCompleteLogout func(body io.Reader, o ...func(*SecuritySamlCompleteLogoutRequest)) (*Response, error)
+
+// SecuritySamlCompleteLogoutRequest configures the Security Saml Complete Logout API request.
+//
+type SecuritySamlCompleteLogoutRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlCompleteLogoutRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/saml/complete_logout"))
+	path.WriteString("/_security/saml/complete_logout")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlCompleteLogout) WithContext(v context.Context) func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlCompleteLogout) WithPretty() func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlCompleteLogout) WithHuman() func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlCompleteLogout) WithErrorTrace() func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlCompleteLogout) WithFilterPath(v ...string) func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlCompleteLogout) WithHeader(h map[string]string) func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlCompleteLogout) WithOpaqueID(s string) func(*SecuritySamlCompleteLogoutRequest) {
+	return func(r *SecuritySamlCompleteLogoutRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_invalidate.go b/esapi/api.xpack.security.saml_invalidate.go
new file mode 100644
index 0000000000..7b32292726
--- /dev/null
+++ b/esapi/api.xpack.security.saml_invalidate.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlInvalidateFunc(t Transport) SecuritySamlInvalidate {
+	return func(body io.Reader, o ...func(*SecuritySamlInvalidateRequest)) (*Response, error) {
+		var r = SecuritySamlInvalidateRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlInvalidate - Consumes a SAML LogoutRequest
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-invalidate.html.
+//
+type SecuritySamlInvalidate func(body io.Reader, o ...func(*SecuritySamlInvalidateRequest)) (*Response, error)
+
+// SecuritySamlInvalidateRequest configures the Security Saml Invalidate API request.
+//
+type SecuritySamlInvalidateRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlInvalidateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/saml/invalidate"))
+	path.WriteString("/_security/saml/invalidate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlInvalidate) WithContext(v context.Context) func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlInvalidate) WithPretty() func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlInvalidate) WithHuman() func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlInvalidate) WithErrorTrace() func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlInvalidate) WithFilterPath(v ...string) func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlInvalidate) WithHeader(h map[string]string) func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlInvalidate) WithOpaqueID(s string) func(*SecuritySamlInvalidateRequest) {
+	return func(r *SecuritySamlInvalidateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_logout.go b/esapi/api.xpack.security.saml_logout.go
new file mode 100644
index 0000000000..76a6d85118
--- /dev/null
+++ b/esapi/api.xpack.security.saml_logout.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlLogoutFunc(t Transport) SecuritySamlLogout {
+	return func(body io.Reader, o ...func(*SecuritySamlLogoutRequest)) (*Response, error) {
+		var r = SecuritySamlLogoutRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlLogout - Invalidates an access token and a refresh token that were generated via the SAML Authenticate API
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-logout.html.
+//
+type SecuritySamlLogout func(body io.Reader, o ...func(*SecuritySamlLogoutRequest)) (*Response, error)
+
+// SecuritySamlLogoutRequest configures the Security Saml Logout API request.
+//
+type SecuritySamlLogoutRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlLogoutRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/saml/logout"))
+	path.WriteString("/_security/saml/logout")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlLogout) WithContext(v context.Context) func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlLogout) WithPretty() func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlLogout) WithHuman() func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlLogout) WithErrorTrace() func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlLogout) WithFilterPath(v ...string) func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlLogout) WithHeader(h map[string]string) func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlLogout) WithOpaqueID(s string) func(*SecuritySamlLogoutRequest) {
+	return func(r *SecuritySamlLogoutRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_prepare_authentication.go b/esapi/api.xpack.security.saml_prepare_authentication.go
new file mode 100644
index 0000000000..dee1a7203d
--- /dev/null
+++ b/esapi/api.xpack.security.saml_prepare_authentication.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlPrepareAuthenticationFunc(t Transport) SecuritySamlPrepareAuthentication {
+	return func(body io.Reader, o ...func(*SecuritySamlPrepareAuthenticationRequest)) (*Response, error) {
+		var r = SecuritySamlPrepareAuthenticationRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlPrepareAuthentication - Creates a SAML authentication request
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-prepare-authentication.html.
+//
+type SecuritySamlPrepareAuthentication func(body io.Reader, o ...func(*SecuritySamlPrepareAuthenticationRequest)) (*Response, error)
+
+// SecuritySamlPrepareAuthenticationRequest configures the Security Saml Prepare Authentication API request.
+//
+type SecuritySamlPrepareAuthenticationRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlPrepareAuthenticationRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_security/saml/prepare"))
+	path.WriteString("/_security/saml/prepare")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlPrepareAuthentication) WithContext(v context.Context) func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlPrepareAuthentication) WithPretty() func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlPrepareAuthentication) WithHuman() func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlPrepareAuthentication) WithErrorTrace() func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlPrepareAuthentication) WithFilterPath(v ...string) func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlPrepareAuthentication) WithHeader(h map[string]string) func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlPrepareAuthentication) WithOpaqueID(s string) func(*SecuritySamlPrepareAuthenticationRequest) {
+	return func(r *SecuritySamlPrepareAuthenticationRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.security.saml_service_provider_metadata.go b/esapi/api.xpack.security.saml_service_provider_metadata.go
new file mode 100644
index 0000000000..7b5ca8489f
--- /dev/null
+++ b/esapi/api.xpack.security.saml_service_provider_metadata.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSecuritySamlServiceProviderMetadataFunc(t Transport) SecuritySamlServiceProviderMetadata {
+	return func(realm_name string, o ...func(*SecuritySamlServiceProviderMetadataRequest)) (*Response, error) {
+		var r = SecuritySamlServiceProviderMetadataRequest{RealmName: realm_name}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SecuritySamlServiceProviderMetadata - Generates SAML metadata for the Elastic stack SAML 2.0 Service Provider
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-saml-sp-metadata.html.
+//
+type SecuritySamlServiceProviderMetadata func(realm_name string, o ...func(*SecuritySamlServiceProviderMetadataRequest)) (*Response, error)
+
+// SecuritySamlServiceProviderMetadataRequest configures the Security Saml Service Provider Metadata API request.
+//
+type SecuritySamlServiceProviderMetadataRequest struct {
+	RealmName string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SecuritySamlServiceProviderMetadataRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_security") + 1 + len("saml") + 1 + len("metadata") + 1 + len(r.RealmName))
+	path.WriteString("/")
+	path.WriteString("_security")
+	path.WriteString("/")
+	path.WriteString("saml")
+	path.WriteString("/")
+	path.WriteString("metadata")
+	path.WriteString("/")
+	path.WriteString(r.RealmName)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SecuritySamlServiceProviderMetadata) WithContext(v context.Context) func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SecuritySamlServiceProviderMetadata) WithPretty() func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SecuritySamlServiceProviderMetadata) WithHuman() func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SecuritySamlServiceProviderMetadata) WithErrorTrace() func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SecuritySamlServiceProviderMetadata) WithFilterPath(v ...string) func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SecuritySamlServiceProviderMetadata) WithHeader(h map[string]string) func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SecuritySamlServiceProviderMetadata) WithOpaqueID(s string) func(*SecuritySamlServiceProviderMetadataRequest) {
+	return func(r *SecuritySamlServiceProviderMetadataRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.delete_lifecycle.go b/esapi/api.xpack.slm.delete_lifecycle.go
new file mode 100644
index 0000000000..f3710d76a1
--- /dev/null
+++ b/esapi/api.xpack.slm.delete_lifecycle.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmDeleteLifecycleFunc(t Transport) SlmDeleteLifecycle {
+	return func(policy_id string, o ...func(*SlmDeleteLifecycleRequest)) (*Response, error) {
+		var r = SlmDeleteLifecycleRequest{PolicyID: policy_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmDeleteLifecycle - Deletes an existing snapshot lifecycle policy.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-delete-policy.html.
+//
+type SlmDeleteLifecycle func(policy_id string, o ...func(*SlmDeleteLifecycleRequest)) (*Response, error)
+
+// SlmDeleteLifecycleRequest configures the Slm Delete Lifecycle API request.
+//
+type SlmDeleteLifecycleRequest struct {
+	PolicyID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmDeleteLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_slm") + 1 + len("policy") + 1 + len(r.PolicyID))
+	path.WriteString("/")
+	path.WriteString("_slm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.PolicyID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmDeleteLifecycle) WithContext(v context.Context) func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmDeleteLifecycle) WithPretty() func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmDeleteLifecycle) WithHuman() func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmDeleteLifecycle) WithErrorTrace() func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmDeleteLifecycle) WithFilterPath(v ...string) func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmDeleteLifecycle) WithHeader(h map[string]string) func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmDeleteLifecycle) WithOpaqueID(s string) func(*SlmDeleteLifecycleRequest) {
+	return func(r *SlmDeleteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.execute_lifecycle.go b/esapi/api.xpack.slm.execute_lifecycle.go
new file mode 100644
index 0000000000..4679aaaea2
--- /dev/null
+++ b/esapi/api.xpack.slm.execute_lifecycle.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmExecuteLifecycleFunc(t Transport) SlmExecuteLifecycle {
+	return func(policy_id string, o ...func(*SlmExecuteLifecycleRequest)) (*Response, error) {
+		var r = SlmExecuteLifecycleRequest{PolicyID: policy_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmExecuteLifecycle - Immediately creates a snapshot according to the lifecycle policy, without waiting for the scheduled time.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-execute-lifecycle.html.
+//
+type SlmExecuteLifecycle func(policy_id string, o ...func(*SlmExecuteLifecycleRequest)) (*Response, error)
+
+// SlmExecuteLifecycleRequest configures the Slm Execute Lifecycle API request.
+//
+type SlmExecuteLifecycleRequest struct {
+	PolicyID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmExecuteLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_slm") + 1 + len("policy") + 1 + len(r.PolicyID) + 1 + len("_execute"))
+	path.WriteString("/")
+	path.WriteString("_slm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.PolicyID)
+	path.WriteString("/")
+	path.WriteString("_execute")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmExecuteLifecycle) WithContext(v context.Context) func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmExecuteLifecycle) WithPretty() func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmExecuteLifecycle) WithHuman() func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmExecuteLifecycle) WithErrorTrace() func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmExecuteLifecycle) WithFilterPath(v ...string) func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmExecuteLifecycle) WithHeader(h map[string]string) func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmExecuteLifecycle) WithOpaqueID(s string) func(*SlmExecuteLifecycleRequest) {
+	return func(r *SlmExecuteLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.execute_retention.go b/esapi/api.xpack.slm.execute_retention.go
new file mode 100644
index 0000000000..1529fe94d7
--- /dev/null
+++ b/esapi/api.xpack.slm.execute_retention.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmExecuteRetentionFunc(t Transport) SlmExecuteRetention {
+	return func(o ...func(*SlmExecuteRetentionRequest)) (*Response, error) {
+		var r = SlmExecuteRetentionRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmExecuteRetention - Deletes any snapshots that are expired according to the policy's retention rules.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-execute-retention.html.
+//
+type SlmExecuteRetention func(o ...func(*SlmExecuteRetentionRequest)) (*Response, error)
+
+// SlmExecuteRetentionRequest configures the Slm Execute Retention API request.
+//
+type SlmExecuteRetentionRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmExecuteRetentionRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_slm/_execute_retention"))
+	path.WriteString("/_slm/_execute_retention")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmExecuteRetention) WithContext(v context.Context) func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmExecuteRetention) WithPretty() func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmExecuteRetention) WithHuman() func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmExecuteRetention) WithErrorTrace() func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmExecuteRetention) WithFilterPath(v ...string) func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmExecuteRetention) WithHeader(h map[string]string) func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmExecuteRetention) WithOpaqueID(s string) func(*SlmExecuteRetentionRequest) {
+	return func(r *SlmExecuteRetentionRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.get_lifecycle.go b/esapi/api.xpack.slm.get_lifecycle.go
new file mode 100644
index 0000000000..9c5cd84905
--- /dev/null
+++ b/esapi/api.xpack.slm.get_lifecycle.go
@@ -0,0 +1,213 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmGetLifecycleFunc(t Transport) SlmGetLifecycle {
+	return func(o ...func(*SlmGetLifecycleRequest)) (*Response, error) {
+		var r = SlmGetLifecycleRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmGetLifecycle - Retrieves one or more snapshot lifecycle policy definitions and information about the latest snapshot attempts.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-get-policy.html.
+//
+type SlmGetLifecycle func(o ...func(*SlmGetLifecycleRequest)) (*Response, error)
+
+// SlmGetLifecycleRequest configures the Slm Get Lifecycle API request.
+//
+type SlmGetLifecycleRequest struct {
+	PolicyID []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmGetLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_slm") + 1 + len("policy") + 1 + len(strings.Join(r.PolicyID, ",")))
+	path.WriteString("/")
+	path.WriteString("_slm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	if len(r.PolicyID) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.PolicyID, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmGetLifecycle) WithContext(v context.Context) func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPolicyID - comma-separated list of snapshot lifecycle policies to retrieve.
+//
+func (f SlmGetLifecycle) WithPolicyID(v ...string) func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.PolicyID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmGetLifecycle) WithPretty() func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmGetLifecycle) WithHuman() func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmGetLifecycle) WithErrorTrace() func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmGetLifecycle) WithFilterPath(v ...string) func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmGetLifecycle) WithHeader(h map[string]string) func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmGetLifecycle) WithOpaqueID(s string) func(*SlmGetLifecycleRequest) {
+	return func(r *SlmGetLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.get_stats.go b/esapi/api.xpack.slm.get_stats.go
new file mode 100644
index 0000000000..5ee78d8155
--- /dev/null
+++ b/esapi/api.xpack.slm.get_stats.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmGetStatsFunc(t Transport) SlmGetStats {
+	return func(o ...func(*SlmGetStatsRequest)) (*Response, error) {
+		var r = SlmGetStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmGetStats - Returns global and policy-level statistics about actions taken by snapshot lifecycle management.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/slm-api-get-stats.html.
+//
+type SlmGetStats func(o ...func(*SlmGetStatsRequest)) (*Response, error)
+
+// SlmGetStatsRequest configures the Slm Get Stats API request.
+//
+type SlmGetStatsRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmGetStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_slm/stats"))
+	path.WriteString("/_slm/stats")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmGetStats) WithContext(v context.Context) func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmGetStats) WithPretty() func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmGetStats) WithHuman() func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmGetStats) WithErrorTrace() func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmGetStats) WithFilterPath(v ...string) func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmGetStats) WithHeader(h map[string]string) func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmGetStats) WithOpaqueID(s string) func(*SlmGetStatsRequest) {
+	return func(r *SlmGetStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.get_status.go b/esapi/api.xpack.slm.get_status.go
new file mode 100644
index 0000000000..89481c1545
--- /dev/null
+++ b/esapi/api.xpack.slm.get_status.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmGetStatusFunc(t Transport) SlmGetStatus {
+	return func(o ...func(*SlmGetStatusRequest)) (*Response, error) {
+		var r = SlmGetStatusRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmGetStatus - Retrieves the status of snapshot lifecycle management (SLM).
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-get-status.html.
+//
+type SlmGetStatus func(o ...func(*SlmGetStatusRequest)) (*Response, error)
+
+// SlmGetStatusRequest configures the Slm Get Status API request.
+//
+type SlmGetStatusRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmGetStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_slm/status"))
+	path.WriteString("/_slm/status")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmGetStatus) WithContext(v context.Context) func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmGetStatus) WithPretty() func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmGetStatus) WithHuman() func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmGetStatus) WithErrorTrace() func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmGetStatus) WithFilterPath(v ...string) func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmGetStatus) WithHeader(h map[string]string) func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmGetStatus) WithOpaqueID(s string) func(*SlmGetStatusRequest) {
+	return func(r *SlmGetStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.put_lifecycle.go b/esapi/api.xpack.slm.put_lifecycle.go
new file mode 100644
index 0000000000..ceb3b8c65c
--- /dev/null
+++ b/esapi/api.xpack.slm.put_lifecycle.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSlmPutLifecycleFunc(t Transport) SlmPutLifecycle {
+	return func(policy_id string, o ...func(*SlmPutLifecycleRequest)) (*Response, error) {
+		var r = SlmPutLifecycleRequest{PolicyID: policy_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmPutLifecycle - Creates or updates a snapshot lifecycle policy.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-put-policy.html.
+//
+type SlmPutLifecycle func(policy_id string, o ...func(*SlmPutLifecycleRequest)) (*Response, error)
+
+// SlmPutLifecycleRequest configures the Slm Put Lifecycle API request.
+//
+type SlmPutLifecycleRequest struct {
+	Body io.Reader
+
+	PolicyID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmPutLifecycleRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_slm") + 1 + len("policy") + 1 + len(r.PolicyID))
+	path.WriteString("/")
+	path.WriteString("_slm")
+	path.WriteString("/")
+	path.WriteString("policy")
+	path.WriteString("/")
+	path.WriteString(r.PolicyID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmPutLifecycle) WithContext(v context.Context) func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The snapshot lifecycle policy definition to register.
+//
+func (f SlmPutLifecycle) WithBody(v io.Reader) func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmPutLifecycle) WithPretty() func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmPutLifecycle) WithHuman() func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmPutLifecycle) WithErrorTrace() func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmPutLifecycle) WithFilterPath(v ...string) func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmPutLifecycle) WithHeader(h map[string]string) func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmPutLifecycle) WithOpaqueID(s string) func(*SlmPutLifecycleRequest) {
+	return func(r *SlmPutLifecycleRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.start.go b/esapi/api.xpack.slm.start.go
new file mode 100644
index 0000000000..fe3b2ff973
--- /dev/null
+++ b/esapi/api.xpack.slm.start.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmStartFunc(t Transport) SlmStart {
+	return func(o ...func(*SlmStartRequest)) (*Response, error) {
+		var r = SlmStartRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmStart - Turns on snapshot lifecycle management (SLM).
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-start.html.
+//
+type SlmStart func(o ...func(*SlmStartRequest)) (*Response, error)
+
+// SlmStartRequest configures the Slm Start API request.
+//
+type SlmStartRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmStartRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_slm/start"))
+	path.WriteString("/_slm/start")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmStart) WithContext(v context.Context) func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmStart) WithPretty() func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmStart) WithHuman() func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmStart) WithErrorTrace() func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmStart) WithFilterPath(v ...string) func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmStart) WithHeader(h map[string]string) func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmStart) WithOpaqueID(s string) func(*SlmStartRequest) {
+	return func(r *SlmStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.slm.stop.go b/esapi/api.xpack.slm.stop.go
new file mode 100644
index 0000000000..98bf724248
--- /dev/null
+++ b/esapi/api.xpack.slm.stop.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSlmStopFunc(t Transport) SlmStop {
+	return func(o ...func(*SlmStopRequest)) (*Response, error) {
+		var r = SlmStopRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SlmStop - Turns off snapshot lifecycle management (SLM).
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-stop.html.
+//
+type SlmStop func(o ...func(*SlmStopRequest)) (*Response, error)
+
+// SlmStopRequest configures the Slm Stop API request.
+//
+type SlmStopRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SlmStopRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_slm/stop"))
+	path.WriteString("/_slm/stop")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SlmStop) WithContext(v context.Context) func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SlmStop) WithPretty() func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SlmStop) WithHuman() func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SlmStop) WithErrorTrace() func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SlmStop) WithFilterPath(v ...string) func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SlmStop) WithHeader(h map[string]string) func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SlmStop) WithOpaqueID(s string) func(*SlmStopRequest) {
+	return func(r *SlmStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.clear_cursor.go b/esapi/api.xpack.sql.clear_cursor.go
new file mode 100644
index 0000000000..5d9156acbc
--- /dev/null
+++ b/esapi/api.xpack.sql.clear_cursor.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSQLClearCursorFunc(t Transport) SQLClearCursor {
+	return func(body io.Reader, o ...func(*SQLClearCursorRequest)) (*Response, error) {
+		var r = SQLClearCursorRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLClearCursor - Clears the SQL cursor
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/clear-sql-cursor-api.html.
+//
+type SQLClearCursor func(body io.Reader, o ...func(*SQLClearCursorRequest)) (*Response, error)
+
+// SQLClearCursorRequest configures the SQL Clear Cursor API request.
+//
+type SQLClearCursorRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLClearCursorRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_sql/close"))
+	path.WriteString("/_sql/close")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLClearCursor) WithContext(v context.Context) func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLClearCursor) WithPretty() func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLClearCursor) WithHuman() func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLClearCursor) WithErrorTrace() func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLClearCursor) WithFilterPath(v ...string) func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLClearCursor) WithHeader(h map[string]string) func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLClearCursor) WithOpaqueID(s string) func(*SQLClearCursorRequest) {
+	return func(r *SQLClearCursorRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.delete_async.go b/esapi/api.xpack.sql.delete_async.go
new file mode 100644
index 0000000000..ad09eabe01
--- /dev/null
+++ b/esapi/api.xpack.sql.delete_async.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSQLDeleteAsyncFunc(t Transport) SQLDeleteAsync {
+	return func(id string, o ...func(*SQLDeleteAsyncRequest)) (*Response, error) {
+		var r = SQLDeleteAsyncRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLDeleteAsync - Deletes an async SQL search or a stored synchronous SQL search. If the search is still running, the API cancels it.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/delete-async-sql-search-api.html.
+//
+type SQLDeleteAsync func(id string, o ...func(*SQLDeleteAsyncRequest)) (*Response, error)
+
+// SQLDeleteAsyncRequest configures the SQL Delete Async API request.
+//
+type SQLDeleteAsyncRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLDeleteAsyncRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_sql") + 1 + len("async") + 1 + len("delete") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_sql")
+	path.WriteString("/")
+	path.WriteString("async")
+	path.WriteString("/")
+	path.WriteString("delete")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLDeleteAsync) WithContext(v context.Context) func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLDeleteAsync) WithPretty() func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLDeleteAsync) WithHuman() func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLDeleteAsync) WithErrorTrace() func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLDeleteAsync) WithFilterPath(v ...string) func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLDeleteAsync) WithHeader(h map[string]string) func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLDeleteAsync) WithOpaqueID(s string) func(*SQLDeleteAsyncRequest) {
+	return func(r *SQLDeleteAsyncRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.get_async.go b/esapi/api.xpack.sql.get_async.go
new file mode 100644
index 0000000000..d490e2d7bd
--- /dev/null
+++ b/esapi/api.xpack.sql.get_async.go
@@ -0,0 +1,257 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newSQLGetAsyncFunc(t Transport) SQLGetAsync {
+	return func(id string, o ...func(*SQLGetAsyncRequest)) (*Response, error) {
+		var r = SQLGetAsyncRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLGetAsync - Returns the current status and available results for an async SQL search or stored synchronous SQL search
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-async-sql-search-api.html.
+//
+type SQLGetAsync func(id string, o ...func(*SQLGetAsyncRequest)) (*Response, error)
+
+// SQLGetAsyncRequest configures the SQL Get Async API request.
+//
+type SQLGetAsyncRequest struct {
+	DocumentID string
+
+	Delimiter                string
+	Format                   string
+	KeepAlive                time.Duration
+	WaitForCompletionTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLGetAsyncRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_sql") + 1 + len("async") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_sql")
+	path.WriteString("/")
+	path.WriteString("async")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Delimiter != "" {
+		params["delimiter"] = r.Delimiter
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.KeepAlive != 0 {
+		params["keep_alive"] = formatDuration(r.KeepAlive)
+	}
+
+	if r.WaitForCompletionTimeout != 0 {
+		params["wait_for_completion_timeout"] = formatDuration(r.WaitForCompletionTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLGetAsync) WithContext(v context.Context) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDelimiter - separator for csv results.
+//
+func (f SQLGetAsync) WithDelimiter(v string) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.Delimiter = v
+	}
+}
+
+// WithFormat - short version of the accept header, e.g. json, yaml.
+//
+func (f SQLGetAsync) WithFormat(v string) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.Format = v
+	}
+}
+
+// WithKeepAlive - retention period for the search and its results.
+//
+func (f SQLGetAsync) WithKeepAlive(v time.Duration) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.KeepAlive = v
+	}
+}
+
+// WithWaitForCompletionTimeout - duration to wait for complete results.
+//
+func (f SQLGetAsync) WithWaitForCompletionTimeout(v time.Duration) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.WaitForCompletionTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLGetAsync) WithPretty() func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLGetAsync) WithHuman() func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLGetAsync) WithErrorTrace() func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLGetAsync) WithFilterPath(v ...string) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLGetAsync) WithHeader(h map[string]string) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLGetAsync) WithOpaqueID(s string) func(*SQLGetAsyncRequest) {
+	return func(r *SQLGetAsyncRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.get_async_status.go b/esapi/api.xpack.sql.get_async_status.go
new file mode 100644
index 0000000000..f623daa037
--- /dev/null
+++ b/esapi/api.xpack.sql.get_async_status.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSQLGetAsyncStatusFunc(t Transport) SQLGetAsyncStatus {
+	return func(id string, o ...func(*SQLGetAsyncStatusRequest)) (*Response, error) {
+		var r = SQLGetAsyncStatusRequest{DocumentID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLGetAsyncStatus - Returns the current status of an async SQL search or a stored synchronous SQL search
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/master/get-async-sql-search-status-api.html.
+//
+type SQLGetAsyncStatus func(id string, o ...func(*SQLGetAsyncStatusRequest)) (*Response, error)
+
+// SQLGetAsyncStatusRequest configures the SQL Get Async Status API request.
+//
+type SQLGetAsyncStatusRequest struct {
+	DocumentID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLGetAsyncStatusRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_sql") + 1 + len("async") + 1 + len("status") + 1 + len(r.DocumentID))
+	path.WriteString("/")
+	path.WriteString("_sql")
+	path.WriteString("/")
+	path.WriteString("async")
+	path.WriteString("/")
+	path.WriteString("status")
+	path.WriteString("/")
+	path.WriteString(r.DocumentID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLGetAsyncStatus) WithContext(v context.Context) func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLGetAsyncStatus) WithPretty() func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLGetAsyncStatus) WithHuman() func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLGetAsyncStatus) WithErrorTrace() func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLGetAsyncStatus) WithFilterPath(v ...string) func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLGetAsyncStatus) WithHeader(h map[string]string) func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLGetAsyncStatus) WithOpaqueID(s string) func(*SQLGetAsyncStatusRequest) {
+	return func(r *SQLGetAsyncStatusRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.query.go b/esapi/api.xpack.sql.query.go
new file mode 100644
index 0000000000..b3a8698b13
--- /dev/null
+++ b/esapi/api.xpack.sql.query.go
@@ -0,0 +1,217 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSQLQueryFunc(t Transport) SQLQuery {
+	return func(body io.Reader, o ...func(*SQLQueryRequest)) (*Response, error) {
+		var r = SQLQueryRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLQuery - Executes a SQL request
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-search-api.html.
+//
+type SQLQuery func(body io.Reader, o ...func(*SQLQueryRequest)) (*Response, error)
+
+// SQLQueryRequest configures the SQL Query API request.
+//
+type SQLQueryRequest struct {
+	Body io.Reader
+
+	Format string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLQueryRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_sql"))
+	path.WriteString("/_sql")
+
+	params = make(map[string]string)
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLQuery) WithContext(v context.Context) func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.ctx = v
+	}
+}
+
+// WithFormat - a short version of the accept header, e.g. json, yaml.
+//
+func (f SQLQuery) WithFormat(v string) func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.Format = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLQuery) WithPretty() func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLQuery) WithHuman() func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLQuery) WithErrorTrace() func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLQuery) WithFilterPath(v ...string) func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLQuery) WithHeader(h map[string]string) func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLQuery) WithOpaqueID(s string) func(*SQLQueryRequest) {
+	return func(r *SQLQueryRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.sql.translate.go b/esapi/api.xpack.sql.translate.go
new file mode 100644
index 0000000000..b85aa103ba
--- /dev/null
+++ b/esapi/api.xpack.sql.translate.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newSQLTranslateFunc(t Transport) SQLTranslate {
+	return func(body io.Reader, o ...func(*SQLTranslateRequest)) (*Response, error) {
+		var r = SQLTranslateRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SQLTranslate - Translates SQL into Elasticsearch queries
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-translate-api.html.
+//
+type SQLTranslate func(body io.Reader, o ...func(*SQLTranslateRequest)) (*Response, error)
+
+// SQLTranslateRequest configures the SQL Translate API request.
+//
+type SQLTranslateRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SQLTranslateRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_sql/translate"))
+	path.WriteString("/_sql/translate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SQLTranslate) WithContext(v context.Context) func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SQLTranslate) WithPretty() func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SQLTranslate) WithHuman() func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SQLTranslate) WithErrorTrace() func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SQLTranslate) WithFilterPath(v ...string) func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SQLTranslate) WithHeader(h map[string]string) func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SQLTranslate) WithOpaqueID(s string) func(*SQLTranslateRequest) {
+	return func(r *SQLTranslateRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.ssl.certificates.go b/esapi/api.xpack.ssl.certificates.go
new file mode 100644
index 0000000000..4692f8810f
--- /dev/null
+++ b/esapi/api.xpack.ssl.certificates.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newSSLCertificatesFunc(t Transport) SSLCertificates {
+	return func(o ...func(*SSLCertificatesRequest)) (*Response, error) {
+		var r = SSLCertificatesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// SSLCertificates - Retrieves information about the X.509 certificates used to encrypt communications in the cluster.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-ssl.html.
+//
+type SSLCertificates func(o ...func(*SSLCertificatesRequest)) (*Response, error)
+
+// SSLCertificatesRequest configures the SSL Certificates API request.
+//
+type SSLCertificatesRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r SSLCertificatesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_ssl/certificates"))
+	path.WriteString("/_ssl/certificates")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f SSLCertificates) WithContext(v context.Context) func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f SSLCertificates) WithPretty() func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f SSLCertificates) WithHuman() func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f SSLCertificates) WithErrorTrace() func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f SSLCertificates) WithFilterPath(v ...string) func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f SSLCertificates) WithHeader(h map[string]string) func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f SSLCertificates) WithOpaqueID(s string) func(*SSLCertificatesRequest) {
+	return func(r *SSLCertificatesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.text_structure.find_structure.go b/esapi/api.xpack.text_structure.find_structure.go
new file mode 100644
index 0000000000..713ad0f406
--- /dev/null
+++ b/esapi/api.xpack.text_structure.find_structure.go
@@ -0,0 +1,388 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTextStructureFindStructureFunc(t Transport) TextStructureFindStructure {
+	return func(body io.Reader, o ...func(*TextStructureFindStructureRequest)) (*Response, error) {
+		var r = TextStructureFindStructureRequest{Body: body}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TextStructureFindStructure - Finds the structure of a text file. The text file must contain data that is suitable to be ingested into Elasticsearch.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/find-structure.html.
+//
+type TextStructureFindStructure func(body io.Reader, o ...func(*TextStructureFindStructureRequest)) (*Response, error)
+
+// TextStructureFindStructureRequest configures the Text Structure Find Structure API request.
+//
+type TextStructureFindStructureRequest struct {
+	Body io.Reader
+
+	Charset            string
+	ColumnNames        []string
+	Delimiter          string
+	Explain            *bool
+	Format             string
+	GrokPattern        string
+	HasHeaderRow       *bool
+	LineMergeSizeLimit *int
+	LinesToSample      *int
+	Quote              string
+	ShouldTrimFields   *bool
+	Timeout            time.Duration
+	TimestampField     string
+	TimestampFormat    string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TextStructureFindStructureRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_text_structure/find_structure"))
+	path.WriteString("/_text_structure/find_structure")
+
+	params = make(map[string]string)
+
+	if r.Charset != "" {
+		params["charset"] = r.Charset
+	}
+
+	if len(r.ColumnNames) > 0 {
+		params["column_names"] = strings.Join(r.ColumnNames, ",")
+	}
+
+	if r.Delimiter != "" {
+		params["delimiter"] = r.Delimiter
+	}
+
+	if r.Explain != nil {
+		params["explain"] = strconv.FormatBool(*r.Explain)
+	}
+
+	if r.Format != "" {
+		params["format"] = r.Format
+	}
+
+	if r.GrokPattern != "" {
+		params["grok_pattern"] = r.GrokPattern
+	}
+
+	if r.HasHeaderRow != nil {
+		params["has_header_row"] = strconv.FormatBool(*r.HasHeaderRow)
+	}
+
+	if r.LineMergeSizeLimit != nil {
+		params["line_merge_size_limit"] = strconv.FormatInt(int64(*r.LineMergeSizeLimit), 10)
+	}
+
+	if r.LinesToSample != nil {
+		params["lines_to_sample"] = strconv.FormatInt(int64(*r.LinesToSample), 10)
+	}
+
+	if r.Quote != "" {
+		params["quote"] = r.Quote
+	}
+
+	if r.ShouldTrimFields != nil {
+		params["should_trim_fields"] = strconv.FormatBool(*r.ShouldTrimFields)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.TimestampField != "" {
+		params["timestamp_field"] = r.TimestampField
+	}
+
+	if r.TimestampFormat != "" {
+		params["timestamp_format"] = r.TimestampFormat
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TextStructureFindStructure) WithContext(v context.Context) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.ctx = v
+	}
+}
+
+// WithCharset - optional parameter to specify the character set of the file.
+//
+func (f TextStructureFindStructure) WithCharset(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Charset = v
+	}
+}
+
+// WithColumnNames - optional parameter containing a comma separated list of the column names for a delimited file.
+//
+func (f TextStructureFindStructure) WithColumnNames(v ...string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.ColumnNames = v
+	}
+}
+
+// WithDelimiter - optional parameter to specify the delimiter character for a delimited file - must be a single character.
+//
+func (f TextStructureFindStructure) WithDelimiter(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Delimiter = v
+	}
+}
+
+// WithExplain - whether to include a commentary on how the structure was derived.
+//
+func (f TextStructureFindStructure) WithExplain(v bool) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Explain = &v
+	}
+}
+
+// WithFormat - optional parameter to specify the high level file format.
+//
+func (f TextStructureFindStructure) WithFormat(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Format = v
+	}
+}
+
+// WithGrokPattern - optional parameter to specify the grok pattern that should be used to extract fields from messages in a semi-structured text file.
+//
+func (f TextStructureFindStructure) WithGrokPattern(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.GrokPattern = v
+	}
+}
+
+// WithHasHeaderRow - optional parameter to specify whether a delimited file includes the column names in its first row.
+//
+func (f TextStructureFindStructure) WithHasHeaderRow(v bool) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.HasHeaderRow = &v
+	}
+}
+
+// WithLineMergeSizeLimit - maximum number of characters permitted in a single message when lines are merged to create messages..
+//
+func (f TextStructureFindStructure) WithLineMergeSizeLimit(v int) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.LineMergeSizeLimit = &v
+	}
+}
+
+// WithLinesToSample - how many lines of the file should be included in the analysis.
+//
+func (f TextStructureFindStructure) WithLinesToSample(v int) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.LinesToSample = &v
+	}
+}
+
+// WithQuote - optional parameter to specify the quote character for a delimited file - must be a single character.
+//
+func (f TextStructureFindStructure) WithQuote(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Quote = v
+	}
+}
+
+// WithShouldTrimFields - optional parameter to specify whether the values between delimiters in a delimited file should have whitespace trimmed from them.
+//
+func (f TextStructureFindStructure) WithShouldTrimFields(v bool) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.ShouldTrimFields = &v
+	}
+}
+
+// WithTimeout - timeout after which the analysis will be aborted.
+//
+func (f TextStructureFindStructure) WithTimeout(v time.Duration) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithTimestampField - optional parameter to specify the timestamp field in the file.
+//
+func (f TextStructureFindStructure) WithTimestampField(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.TimestampField = v
+	}
+}
+
+// WithTimestampFormat - optional parameter to specify the timestamp format in the file - may be either a joda or java time format.
+//
+func (f TextStructureFindStructure) WithTimestampFormat(v string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.TimestampFormat = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TextStructureFindStructure) WithPretty() func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TextStructureFindStructure) WithHuman() func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TextStructureFindStructure) WithErrorTrace() func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TextStructureFindStructure) WithFilterPath(v ...string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TextStructureFindStructure) WithHeader(h map[string]string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TextStructureFindStructure) WithOpaqueID(s string) func(*TextStructureFindStructureRequest) {
+	return func(r *TextStructureFindStructureRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.delete_transform.go b/esapi/api.xpack.transform.delete_transform.go
new file mode 100644
index 0000000000..c7e003ad0c
--- /dev/null
+++ b/esapi/api.xpack.transform.delete_transform.go
@@ -0,0 +1,230 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTransformDeleteTransformFunc(t Transport) TransformDeleteTransform {
+	return func(transform_id string, o ...func(*TransformDeleteTransformRequest)) (*Response, error) {
+		var r = TransformDeleteTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformDeleteTransform - Deletes an existing transform.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/delete-transform.html.
+//
+type TransformDeleteTransform func(transform_id string, o ...func(*TransformDeleteTransformRequest)) (*Response, error)
+
+// TransformDeleteTransformRequest configures the Transform Delete Transform API request.
+//
+type TransformDeleteTransformRequest struct {
+	TransformID string
+
+	Force   *bool
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformDeleteTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+
+	params = make(map[string]string)
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformDeleteTransform) WithContext(v context.Context) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithForce - when `true`, the transform is deleted regardless of its current state. the default value is `false`, meaning that the transform must be `stopped` before it can be deleted..
+//
+func (f TransformDeleteTransform) WithForce(v bool) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait for the transform deletion.
+//
+func (f TransformDeleteTransform) WithTimeout(v time.Duration) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformDeleteTransform) WithPretty() func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformDeleteTransform) WithHuman() func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformDeleteTransform) WithErrorTrace() func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformDeleteTransform) WithFilterPath(v ...string) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformDeleteTransform) WithHeader(h map[string]string) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformDeleteTransform) WithOpaqueID(s string) func(*TransformDeleteTransformRequest) {
+	return func(r *TransformDeleteTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.get_transform.go b/esapi/api.xpack.transform.get_transform.go
new file mode 100644
index 0000000000..51dbb317ea
--- /dev/null
+++ b/esapi/api.xpack.transform.get_transform.go
@@ -0,0 +1,265 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newTransformGetTransformFunc(t Transport) TransformGetTransform {
+	return func(o ...func(*TransformGetTransformRequest)) (*Response, error) {
+		var r = TransformGetTransformRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformGetTransform - Retrieves configuration information for transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-transform.html.
+//
+type TransformGetTransform func(o ...func(*TransformGetTransformRequest)) (*Response, error)
+
+// TransformGetTransformRequest configures the Transform Get Transform API request.
+//
+type TransformGetTransformRequest struct {
+	TransformID string
+
+	AllowNoMatch     *bool
+	ExcludeGenerated *bool
+	From             *int
+	Size             *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformGetTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	if r.TransformID != "" {
+		path.WriteString("/")
+		path.WriteString(r.TransformID)
+	}
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.ExcludeGenerated != nil {
+		params["exclude_generated"] = strconv.FormatBool(*r.ExcludeGenerated)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformGetTransform) WithContext(v context.Context) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTransformID - the ID or comma delimited list of ID expressions of the transforms to get, '_all' or '*' implies get all transforms.
+//
+func (f TransformGetTransform) WithTransformID(v string) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.TransformID = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f TransformGetTransform) WithAllowNoMatch(v bool) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithExcludeGenerated - omits fields that are illegal to set on transform put.
+//
+func (f TransformGetTransform) WithExcludeGenerated(v bool) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.ExcludeGenerated = &v
+	}
+}
+
+// WithFrom - skips a number of transform configs, defaults to 0.
+//
+func (f TransformGetTransform) WithFrom(v int) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of transforms to get, defaults to 100.
+//
+func (f TransformGetTransform) WithSize(v int) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformGetTransform) WithPretty() func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformGetTransform) WithHuman() func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformGetTransform) WithErrorTrace() func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformGetTransform) WithFilterPath(v ...string) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformGetTransform) WithHeader(h map[string]string) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformGetTransform) WithOpaqueID(s string) func(*TransformGetTransformRequest) {
+	return func(r *TransformGetTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.get_transform_stats.go b/esapi/api.xpack.transform.get_transform_stats.go
new file mode 100644
index 0000000000..40a42efb62
--- /dev/null
+++ b/esapi/api.xpack.transform.get_transform_stats.go
@@ -0,0 +1,244 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newTransformGetTransformStatsFunc(t Transport) TransformGetTransformStats {
+	return func(transform_id string, o ...func(*TransformGetTransformStatsRequest)) (*Response, error) {
+		var r = TransformGetTransformStatsRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformGetTransformStats - Retrieves usage information for transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/get-transform-stats.html.
+//
+type TransformGetTransformStats func(transform_id string, o ...func(*TransformGetTransformStatsRequest)) (*Response, error)
+
+// TransformGetTransformStatsRequest configures the Transform Get Transform Stats API request.
+//
+type TransformGetTransformStatsRequest struct {
+	TransformID string
+
+	AllowNoMatch *bool
+	From         *int
+	Size         *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformGetTransformStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID) + 1 + len("_stats"))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_stats")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.From != nil {
+		params["from"] = strconv.FormatInt(int64(*r.From), 10)
+	}
+
+	if r.Size != nil {
+		params["size"] = strconv.FormatInt(int64(*r.Size), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformGetTransformStats) WithContext(v context.Context) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f TransformGetTransformStats) WithAllowNoMatch(v bool) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithFrom - skips a number of transform stats, defaults to 0.
+//
+func (f TransformGetTransformStats) WithFrom(v int) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.From = &v
+	}
+}
+
+// WithSize - specifies a max number of transform stats to get, defaults to 100.
+//
+func (f TransformGetTransformStats) WithSize(v int) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.Size = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformGetTransformStats) WithPretty() func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformGetTransformStats) WithHuman() func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformGetTransformStats) WithErrorTrace() func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformGetTransformStats) WithFilterPath(v ...string) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformGetTransformStats) WithHeader(h map[string]string) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformGetTransformStats) WithOpaqueID(s string) func(*TransformGetTransformStatsRequest) {
+	return func(r *TransformGetTransformStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.preview_transform.go b/esapi/api.xpack.transform.preview_transform.go
new file mode 100644
index 0000000000..7242a81092
--- /dev/null
+++ b/esapi/api.xpack.transform.preview_transform.go
@@ -0,0 +1,243 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newTransformPreviewTransformFunc(t Transport) TransformPreviewTransform {
+	return func(o ...func(*TransformPreviewTransformRequest)) (*Response, error) {
+		var r = TransformPreviewTransformRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformPreviewTransform - Previews a transform.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/preview-transform.html.
+//
+type TransformPreviewTransform func(o ...func(*TransformPreviewTransformRequest)) (*Response, error)
+
+// TransformPreviewTransformRequest configures the Transform Preview Transform API request.
+//
+type TransformPreviewTransformRequest struct {
+	Body io.Reader
+
+	TransformID string
+
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformPreviewTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID) + 1 + len("_preview"))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	if r.TransformID != "" {
+		path.WriteString("/")
+		path.WriteString(r.TransformID)
+	}
+	path.WriteString("/")
+	path.WriteString("_preview")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformPreviewTransform) WithContext(v context.Context) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The definition for the transform to preview.
+//
+func (f TransformPreviewTransform) WithBody(v io.Reader) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.Body = v
+	}
+}
+
+// WithTransformID - the ID of the transform to preview..
+//
+func (f TransformPreviewTransform) WithTransformID(v string) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.TransformID = v
+	}
+}
+
+// WithTimeout - controls the time to wait for the preview.
+//
+func (f TransformPreviewTransform) WithTimeout(v time.Duration) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformPreviewTransform) WithPretty() func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformPreviewTransform) WithHuman() func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformPreviewTransform) WithErrorTrace() func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformPreviewTransform) WithFilterPath(v ...string) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformPreviewTransform) WithHeader(h map[string]string) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformPreviewTransform) WithOpaqueID(s string) func(*TransformPreviewTransformRequest) {
+	return func(r *TransformPreviewTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.put_transform.go b/esapi/api.xpack.transform.put_transform.go
new file mode 100644
index 0000000000..69b55db6ff
--- /dev/null
+++ b/esapi/api.xpack.transform.put_transform.go
@@ -0,0 +1,237 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTransformPutTransformFunc(t Transport) TransformPutTransform {
+	return func(body io.Reader, transform_id string, o ...func(*TransformPutTransformRequest)) (*Response, error) {
+		var r = TransformPutTransformRequest{Body: body, TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformPutTransform - Instantiates a transform.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/put-transform.html.
+//
+type TransformPutTransform func(body io.Reader, transform_id string, o ...func(*TransformPutTransformRequest)) (*Response, error)
+
+// TransformPutTransformRequest configures the Transform Put Transform API request.
+//
+type TransformPutTransformRequest struct {
+	Body io.Reader
+
+	TransformID string
+
+	DeferValidation *bool
+	Timeout         time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformPutTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+
+	params = make(map[string]string)
+
+	if r.DeferValidation != nil {
+		params["defer_validation"] = strconv.FormatBool(*r.DeferValidation)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformPutTransform) WithContext(v context.Context) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDeferValidation - if validations should be deferred until transform starts, defaults to false..
+//
+func (f TransformPutTransform) WithDeferValidation(v bool) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.DeferValidation = &v
+	}
+}
+
+// WithTimeout - controls the time to wait for the transform to start.
+//
+func (f TransformPutTransform) WithTimeout(v time.Duration) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformPutTransform) WithPretty() func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformPutTransform) WithHuman() func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformPutTransform) WithErrorTrace() func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformPutTransform) WithFilterPath(v ...string) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformPutTransform) WithHeader(h map[string]string) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformPutTransform) WithOpaqueID(s string) func(*TransformPutTransformRequest) {
+	return func(r *TransformPutTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.start_transform.go b/esapi/api.xpack.transform.start_transform.go
new file mode 100644
index 0000000000..7767e7d1d4
--- /dev/null
+++ b/esapi/api.xpack.transform.start_transform.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newTransformStartTransformFunc(t Transport) TransformStartTransform {
+	return func(transform_id string, o ...func(*TransformStartTransformRequest)) (*Response, error) {
+		var r = TransformStartTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformStartTransform - Starts one or more transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/start-transform.html.
+//
+type TransformStartTransform func(transform_id string, o ...func(*TransformStartTransformRequest)) (*Response, error)
+
+// TransformStartTransformRequest configures the Transform Start Transform API request.
+//
+type TransformStartTransformRequest struct {
+	TransformID string
+
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformStartTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID) + 1 + len("_start"))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_start")
+
+	params = make(map[string]string)
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformStartTransform) WithContext(v context.Context) func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithTimeout - controls the time to wait for the transform to start.
+//
+func (f TransformStartTransform) WithTimeout(v time.Duration) func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformStartTransform) WithPretty() func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformStartTransform) WithHuman() func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformStartTransform) WithErrorTrace() func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformStartTransform) WithFilterPath(v ...string) func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformStartTransform) WithHeader(h map[string]string) func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformStartTransform) WithOpaqueID(s string) func(*TransformStartTransformRequest) {
+	return func(r *TransformStartTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.stop_transform.go b/esapi/api.xpack.transform.stop_transform.go
new file mode 100644
index 0000000000..bba5f13962
--- /dev/null
+++ b/esapi/api.xpack.transform.stop_transform.go
@@ -0,0 +1,271 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTransformStopTransformFunc(t Transport) TransformStopTransform {
+	return func(transform_id string, o ...func(*TransformStopTransformRequest)) (*Response, error) {
+		var r = TransformStopTransformRequest{TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformStopTransform - Stops one or more transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/stop-transform.html.
+//
+type TransformStopTransform func(transform_id string, o ...func(*TransformStopTransformRequest)) (*Response, error)
+
+// TransformStopTransformRequest configures the Transform Stop Transform API request.
+//
+type TransformStopTransformRequest struct {
+	TransformID string
+
+	AllowNoMatch      *bool
+	Force             *bool
+	Timeout           time.Duration
+	WaitForCheckpoint *bool
+	WaitForCompletion *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformStopTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID) + 1 + len("_stop"))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_stop")
+
+	params = make(map[string]string)
+
+	if r.AllowNoMatch != nil {
+		params["allow_no_match"] = strconv.FormatBool(*r.AllowNoMatch)
+	}
+
+	if r.Force != nil {
+		params["force"] = strconv.FormatBool(*r.Force)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.WaitForCheckpoint != nil {
+		params["wait_for_checkpoint"] = strconv.FormatBool(*r.WaitForCheckpoint)
+	}
+
+	if r.WaitForCompletion != nil {
+		params["wait_for_completion"] = strconv.FormatBool(*r.WaitForCompletion)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformStopTransform) WithContext(v context.Context) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAllowNoMatch - whether to ignore if a wildcard expression matches no transforms. (this includes `_all` string or when no transforms have been specified).
+//
+func (f TransformStopTransform) WithAllowNoMatch(v bool) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.AllowNoMatch = &v
+	}
+}
+
+// WithForce - whether to force stop a failed transform or not. default to false.
+//
+func (f TransformStopTransform) WithForce(v bool) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.Force = &v
+	}
+}
+
+// WithTimeout - controls the time to wait until the transform has stopped. default to 30 seconds.
+//
+func (f TransformStopTransform) WithTimeout(v time.Duration) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithWaitForCheckpoint - whether to wait for the transform to reach a checkpoint before stopping. default to false.
+//
+func (f TransformStopTransform) WithWaitForCheckpoint(v bool) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.WaitForCheckpoint = &v
+	}
+}
+
+// WithWaitForCompletion - whether to wait for the transform to fully stop before returning or not. default to false.
+//
+func (f TransformStopTransform) WithWaitForCompletion(v bool) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.WaitForCompletion = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformStopTransform) WithPretty() func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformStopTransform) WithHuman() func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformStopTransform) WithErrorTrace() func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformStopTransform) WithFilterPath(v ...string) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformStopTransform) WithHeader(h map[string]string) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformStopTransform) WithOpaqueID(s string) func(*TransformStopTransformRequest) {
+	return func(r *TransformStopTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.update_transform.go b/esapi/api.xpack.transform.update_transform.go
new file mode 100644
index 0000000000..3780a0cbb4
--- /dev/null
+++ b/esapi/api.xpack.transform.update_transform.go
@@ -0,0 +1,239 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTransformUpdateTransformFunc(t Transport) TransformUpdateTransform {
+	return func(body io.Reader, transform_id string, o ...func(*TransformUpdateTransformRequest)) (*Response, error) {
+		var r = TransformUpdateTransformRequest{Body: body, TransformID: transform_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformUpdateTransform - Updates certain properties of a transform.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/update-transform.html.
+//
+type TransformUpdateTransform func(body io.Reader, transform_id string, o ...func(*TransformUpdateTransformRequest)) (*Response, error)
+
+// TransformUpdateTransformRequest configures the Transform Update Transform API request.
+//
+type TransformUpdateTransformRequest struct {
+	Body io.Reader
+
+	TransformID string
+
+	DeferValidation *bool
+	Timeout         time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformUpdateTransformRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(1 + len("_transform") + 1 + len(r.TransformID) + 1 + len("_update"))
+	path.WriteString("/")
+	path.WriteString("_transform")
+	path.WriteString("/")
+	path.WriteString(r.TransformID)
+	path.WriteString("/")
+	path.WriteString("_update")
+
+	params = make(map[string]string)
+
+	if r.DeferValidation != nil {
+		params["defer_validation"] = strconv.FormatBool(*r.DeferValidation)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformUpdateTransform) WithContext(v context.Context) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDeferValidation - if validations should be deferred until transform starts, defaults to false..
+//
+func (f TransformUpdateTransform) WithDeferValidation(v bool) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.DeferValidation = &v
+	}
+}
+
+// WithTimeout - controls the time to wait for the update.
+//
+func (f TransformUpdateTransform) WithTimeout(v time.Duration) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformUpdateTransform) WithPretty() func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformUpdateTransform) WithHuman() func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformUpdateTransform) WithErrorTrace() func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformUpdateTransform) WithFilterPath(v ...string) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformUpdateTransform) WithHeader(h map[string]string) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformUpdateTransform) WithOpaqueID(s string) func(*TransformUpdateTransformRequest) {
+	return func(r *TransformUpdateTransformRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.transform.upgrade_transforms.go b/esapi/api.xpack.transform.upgrade_transforms.go
new file mode 100644
index 0000000000..1309d1e598
--- /dev/null
+++ b/esapi/api.xpack.transform.upgrade_transforms.go
@@ -0,0 +1,225 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func newTransformUpgradeTransformsFunc(t Transport) TransformUpgradeTransforms {
+	return func(o ...func(*TransformUpgradeTransformsRequest)) (*Response, error) {
+		var r = TransformUpgradeTransformsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// TransformUpgradeTransforms - Upgrades all transforms.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/upgrade-transforms.html.
+//
+type TransformUpgradeTransforms func(o ...func(*TransformUpgradeTransformsRequest)) (*Response, error)
+
+// TransformUpgradeTransformsRequest configures the Transform Upgrade Transforms API request.
+//
+type TransformUpgradeTransformsRequest struct {
+	DryRun  *bool
+	Timeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r TransformUpgradeTransformsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_transform/_upgrade"))
+	path.WriteString("/_transform/_upgrade")
+
+	params = make(map[string]string)
+
+	if r.DryRun != nil {
+		params["dry_run"] = strconv.FormatBool(*r.DryRun)
+	}
+
+	if r.Timeout != 0 {
+		params["timeout"] = formatDuration(r.Timeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f TransformUpgradeTransforms) WithContext(v context.Context) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithDryRun - whether to only check for updates but don't execute.
+//
+func (f TransformUpgradeTransforms) WithDryRun(v bool) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.DryRun = &v
+	}
+}
+
+// WithTimeout - controls the time to wait for the upgrade.
+//
+func (f TransformUpgradeTransforms) WithTimeout(v time.Duration) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.Timeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f TransformUpgradeTransforms) WithPretty() func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f TransformUpgradeTransforms) WithHuman() func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f TransformUpgradeTransforms) WithErrorTrace() func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f TransformUpgradeTransforms) WithFilterPath(v ...string) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f TransformUpgradeTransforms) WithHeader(h map[string]string) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f TransformUpgradeTransforms) WithOpaqueID(s string) func(*TransformUpgradeTransformsRequest) {
+	return func(r *TransformUpgradeTransformsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.ack_watch.go b/esapi/api.xpack.watcher.ack_watch.go
new file mode 100644
index 0000000000..0c353ea16f
--- /dev/null
+++ b/esapi/api.xpack.watcher.ack_watch.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherAckWatchFunc(t Transport) WatcherAckWatch {
+	return func(watch_id string, o ...func(*WatcherAckWatchRequest)) (*Response, error) {
+		var r = WatcherAckWatchRequest{WatchID: watch_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherAckWatch - Acknowledges a watch, manually throttling the execution of the watch's actions.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-ack-watch.html.
+//
+type WatcherAckWatch func(watch_id string, o ...func(*WatcherAckWatchRequest)) (*Response, error)
+
+// WatcherAckWatchRequest configures the Watcher Ack Watch API request.
+//
+type WatcherAckWatchRequest struct {
+	ActionID []string
+	WatchID  string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherAckWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID) + 1 + len("_ack") + 1 + len(strings.Join(r.ActionID, ",")))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+	path.WriteString("/")
+	path.WriteString("_ack")
+	if len(r.ActionID) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.ActionID, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherAckWatch) WithContext(v context.Context) func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithActionID - a list of the action ids to be acked.
+//
+func (f WatcherAckWatch) WithActionID(v ...string) func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.ActionID = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherAckWatch) WithPretty() func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherAckWatch) WithHuman() func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherAckWatch) WithErrorTrace() func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherAckWatch) WithFilterPath(v ...string) func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherAckWatch) WithHeader(h map[string]string) func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherAckWatch) WithOpaqueID(s string) func(*WatcherAckWatchRequest) {
+	return func(r *WatcherAckWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.activate_watch.go b/esapi/api.xpack.watcher.activate_watch.go
new file mode 100644
index 0000000000..a3138d15ca
--- /dev/null
+++ b/esapi/api.xpack.watcher.activate_watch.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherActivateWatchFunc(t Transport) WatcherActivateWatch {
+	return func(watch_id string, o ...func(*WatcherActivateWatchRequest)) (*Response, error) {
+		var r = WatcherActivateWatchRequest{WatchID: watch_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherActivateWatch - Activates a currently inactive watch.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-activate-watch.html.
+//
+type WatcherActivateWatch func(watch_id string, o ...func(*WatcherActivateWatchRequest)) (*Response, error)
+
+// WatcherActivateWatchRequest configures the Watcher Activate Watch API request.
+//
+type WatcherActivateWatchRequest struct {
+	WatchID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherActivateWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID) + 1 + len("_activate"))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+	path.WriteString("/")
+	path.WriteString("_activate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherActivateWatch) WithContext(v context.Context) func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherActivateWatch) WithPretty() func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherActivateWatch) WithHuman() func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherActivateWatch) WithErrorTrace() func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherActivateWatch) WithFilterPath(v ...string) func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherActivateWatch) WithHeader(h map[string]string) func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherActivateWatch) WithOpaqueID(s string) func(*WatcherActivateWatchRequest) {
+	return func(r *WatcherActivateWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.deactivate_watch.go b/esapi/api.xpack.watcher.deactivate_watch.go
new file mode 100644
index 0000000000..d36341daf1
--- /dev/null
+++ b/esapi/api.xpack.watcher.deactivate_watch.go
@@ -0,0 +1,205 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherDeactivateWatchFunc(t Transport) WatcherDeactivateWatch {
+	return func(watch_id string, o ...func(*WatcherDeactivateWatchRequest)) (*Response, error) {
+		var r = WatcherDeactivateWatchRequest{WatchID: watch_id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherDeactivateWatch - Deactivates a currently active watch.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-deactivate-watch.html.
+//
+type WatcherDeactivateWatch func(watch_id string, o ...func(*WatcherDeactivateWatchRequest)) (*Response, error)
+
+// WatcherDeactivateWatchRequest configures the Watcher Deactivate Watch API request.
+//
+type WatcherDeactivateWatchRequest struct {
+	WatchID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherDeactivateWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID) + 1 + len("_deactivate"))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+	path.WriteString("/")
+	path.WriteString("_deactivate")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherDeactivateWatch) WithContext(v context.Context) func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherDeactivateWatch) WithPretty() func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherDeactivateWatch) WithHuman() func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherDeactivateWatch) WithErrorTrace() func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherDeactivateWatch) WithFilterPath(v ...string) func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherDeactivateWatch) WithHeader(h map[string]string) func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherDeactivateWatch) WithOpaqueID(s string) func(*WatcherDeactivateWatchRequest) {
+	return func(r *WatcherDeactivateWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.delete_watch.go b/esapi/api.xpack.watcher.delete_watch.go
new file mode 100644
index 0000000000..0f39b26f7d
--- /dev/null
+++ b/esapi/api.xpack.watcher.delete_watch.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherDeleteWatchFunc(t Transport) WatcherDeleteWatch {
+	return func(id string, o ...func(*WatcherDeleteWatchRequest)) (*Response, error) {
+		var r = WatcherDeleteWatchRequest{WatchID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherDeleteWatch - Removes a watch from Watcher.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-delete-watch.html.
+//
+type WatcherDeleteWatch func(id string, o ...func(*WatcherDeleteWatchRequest)) (*Response, error)
+
+// WatcherDeleteWatchRequest configures the Watcher Delete Watch API request.
+//
+type WatcherDeleteWatchRequest struct {
+	WatchID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherDeleteWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "DELETE"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherDeleteWatch) WithContext(v context.Context) func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherDeleteWatch) WithPretty() func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherDeleteWatch) WithHuman() func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherDeleteWatch) WithErrorTrace() func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherDeleteWatch) WithFilterPath(v ...string) func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherDeleteWatch) WithHeader(h map[string]string) func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherDeleteWatch) WithOpaqueID(s string) func(*WatcherDeleteWatchRequest) {
+	return func(r *WatcherDeleteWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.execute_watch.go b/esapi/api.xpack.watcher.execute_watch.go
new file mode 100644
index 0000000000..755fecc28e
--- /dev/null
+++ b/esapi/api.xpack.watcher.execute_watch.go
@@ -0,0 +1,245 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newWatcherExecuteWatchFunc(t Transport) WatcherExecuteWatch {
+	return func(o ...func(*WatcherExecuteWatchRequest)) (*Response, error) {
+		var r = WatcherExecuteWatchRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherExecuteWatch - Forces the execution of a stored watch.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-execute-watch.html.
+//
+type WatcherExecuteWatch func(o ...func(*WatcherExecuteWatchRequest)) (*Response, error)
+
+// WatcherExecuteWatchRequest configures the Watcher Execute Watch API request.
+//
+type WatcherExecuteWatchRequest struct {
+	WatchID string
+
+	Body io.Reader
+
+	Debug *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherExecuteWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID) + 1 + len("_execute"))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	if r.WatchID != "" {
+		path.WriteString("/")
+		path.WriteString(r.WatchID)
+	}
+	path.WriteString("/")
+	path.WriteString("_execute")
+
+	params = make(map[string]string)
+
+	if r.Debug != nil {
+		params["debug"] = strconv.FormatBool(*r.Debug)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherExecuteWatch) WithContext(v context.Context) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - Execution control.
+//
+func (f WatcherExecuteWatch) WithBody(v io.Reader) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.Body = v
+	}
+}
+
+// WithWatchID - watch ID.
+//
+func (f WatcherExecuteWatch) WithWatchID(v string) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.WatchID = v
+	}
+}
+
+// WithDebug - indicates whether the watch should execute in debug mode.
+//
+func (f WatcherExecuteWatch) WithDebug(v bool) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.Debug = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherExecuteWatch) WithPretty() func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherExecuteWatch) WithHuman() func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherExecuteWatch) WithErrorTrace() func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherExecuteWatch) WithFilterPath(v ...string) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherExecuteWatch) WithHeader(h map[string]string) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherExecuteWatch) WithOpaqueID(s string) func(*WatcherExecuteWatchRequest) {
+	return func(r *WatcherExecuteWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.get_watch.go b/esapi/api.xpack.watcher.get_watch.go
new file mode 100644
index 0000000000..d7b131c485
--- /dev/null
+++ b/esapi/api.xpack.watcher.get_watch.go
@@ -0,0 +1,203 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherGetWatchFunc(t Transport) WatcherGetWatch {
+	return func(id string, o ...func(*WatcherGetWatchRequest)) (*Response, error) {
+		var r = WatcherGetWatchRequest{WatchID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherGetWatch - Retrieves a watch by its ID.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-get-watch.html.
+//
+type WatcherGetWatch func(id string, o ...func(*WatcherGetWatchRequest)) (*Response, error)
+
+// WatcherGetWatchRequest configures the Watcher Get Watch API request.
+//
+type WatcherGetWatchRequest struct {
+	WatchID string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherGetWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherGetWatch) WithContext(v context.Context) func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherGetWatch) WithPretty() func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherGetWatch) WithHuman() func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherGetWatch) WithErrorTrace() func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherGetWatch) WithFilterPath(v ...string) func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherGetWatch) WithHeader(h map[string]string) func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherGetWatch) WithOpaqueID(s string) func(*WatcherGetWatchRequest) {
+	return func(r *WatcherGetWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.put_watch.go b/esapi/api.xpack.watcher.put_watch.go
new file mode 100644
index 0000000000..447d59cb80
--- /dev/null
+++ b/esapi/api.xpack.watcher.put_watch.go
@@ -0,0 +1,272 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newWatcherPutWatchFunc(t Transport) WatcherPutWatch {
+	return func(id string, o ...func(*WatcherPutWatchRequest)) (*Response, error) {
+		var r = WatcherPutWatchRequest{WatchID: id}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherPutWatch - Creates a new watch, or updates an existing one.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-put-watch.html.
+//
+type WatcherPutWatch func(id string, o ...func(*WatcherPutWatchRequest)) (*Response, error)
+
+// WatcherPutWatchRequest configures the Watcher Put Watch API request.
+//
+type WatcherPutWatchRequest struct {
+	WatchID string
+
+	Body io.Reader
+
+	Active        *bool
+	IfPrimaryTerm *int
+	IfSeqNo       *int
+	Version       *int
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherPutWatchRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "PUT"
+
+	path.Grow(1 + len("_watcher") + 1 + len("watch") + 1 + len(r.WatchID))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("watch")
+	path.WriteString("/")
+	path.WriteString(r.WatchID)
+
+	params = make(map[string]string)
+
+	if r.Active != nil {
+		params["active"] = strconv.FormatBool(*r.Active)
+	}
+
+	if r.IfPrimaryTerm != nil {
+		params["if_primary_term"] = strconv.FormatInt(int64(*r.IfPrimaryTerm), 10)
+	}
+
+	if r.IfSeqNo != nil {
+		params["if_seq_no"] = strconv.FormatInt(int64(*r.IfSeqNo), 10)
+	}
+
+	if r.Version != nil {
+		params["version"] = strconv.FormatInt(int64(*r.Version), 10)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherPutWatch) WithContext(v context.Context) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - The watch.
+//
+func (f WatcherPutWatch) WithBody(v io.Reader) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.Body = v
+	}
+}
+
+// WithActive - specify whether the watch is in/active by default.
+//
+func (f WatcherPutWatch) WithActive(v bool) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.Active = &v
+	}
+}
+
+// WithIfPrimaryTerm - only update the watch if the last operation that has changed the watch has the specified primary term.
+//
+func (f WatcherPutWatch) WithIfPrimaryTerm(v int) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.IfPrimaryTerm = &v
+	}
+}
+
+// WithIfSeqNo - only update the watch if the last operation that has changed the watch has the specified sequence number.
+//
+func (f WatcherPutWatch) WithIfSeqNo(v int) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.IfSeqNo = &v
+	}
+}
+
+// WithVersion - explicit version number for concurrency control.
+//
+func (f WatcherPutWatch) WithVersion(v int) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.Version = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherPutWatch) WithPretty() func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherPutWatch) WithHuman() func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherPutWatch) WithErrorTrace() func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherPutWatch) WithFilterPath(v ...string) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherPutWatch) WithHeader(h map[string]string) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherPutWatch) WithOpaqueID(s string) func(*WatcherPutWatchRequest) {
+	return func(r *WatcherPutWatchRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.query_watches.go b/esapi/api.xpack.watcher.query_watches.go
new file mode 100644
index 0000000000..0197f220dd
--- /dev/null
+++ b/esapi/api.xpack.watcher.query_watches.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"strings"
+)
+
+func newWatcherQueryWatchesFunc(t Transport) WatcherQueryWatches {
+	return func(o ...func(*WatcherQueryWatchesRequest)) (*Response, error) {
+		var r = WatcherQueryWatchesRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherQueryWatches - Retrieves stored watches.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-query-watches.html.
+//
+type WatcherQueryWatches func(o ...func(*WatcherQueryWatchesRequest)) (*Response, error)
+
+// WatcherQueryWatchesRequest configures the Watcher Query Watches API request.
+//
+type WatcherQueryWatchesRequest struct {
+	Body io.Reader
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherQueryWatchesRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_watcher/_query/watches"))
+	path.WriteString("/_watcher/_query/watches")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), r.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if r.Body != nil {
+		req.Header[headerContentType] = headerContentTypeJSON
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherQueryWatches) WithContext(v context.Context) func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.ctx = v
+	}
+}
+
+// WithBody - From, size, query, sort and search_after.
+//
+func (f WatcherQueryWatches) WithBody(v io.Reader) func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.Body = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherQueryWatches) WithPretty() func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherQueryWatches) WithHuman() func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherQueryWatches) WithErrorTrace() func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherQueryWatches) WithFilterPath(v ...string) func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherQueryWatches) WithHeader(h map[string]string) func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherQueryWatches) WithOpaqueID(s string) func(*WatcherQueryWatchesRequest) {
+	return func(r *WatcherQueryWatchesRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.start.go b/esapi/api.xpack.watcher.start.go
new file mode 100644
index 0000000000..47f2564f31
--- /dev/null
+++ b/esapi/api.xpack.watcher.start.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherStartFunc(t Transport) WatcherStart {
+	return func(o ...func(*WatcherStartRequest)) (*Response, error) {
+		var r = WatcherStartRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherStart - Starts Watcher if it is not already running.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html.
+//
+type WatcherStart func(o ...func(*WatcherStartRequest)) (*Response, error)
+
+// WatcherStartRequest configures the Watcher Start API request.
+//
+type WatcherStartRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherStartRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_watcher/_start"))
+	path.WriteString("/_watcher/_start")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherStart) WithContext(v context.Context) func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherStart) WithPretty() func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherStart) WithHuman() func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherStart) WithErrorTrace() func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherStart) WithFilterPath(v ...string) func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherStart) WithHeader(h map[string]string) func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherStart) WithOpaqueID(s string) func(*WatcherStartRequest) {
+	return func(r *WatcherStartRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.stats.go b/esapi/api.xpack.watcher.stats.go
new file mode 100644
index 0000000000..224620c943
--- /dev/null
+++ b/esapi/api.xpack.watcher.stats.go
@@ -0,0 +1,232 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newWatcherStatsFunc(t Transport) WatcherStats {
+	return func(o ...func(*WatcherStatsRequest)) (*Response, error) {
+		var r = WatcherStatsRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherStats - Retrieves the current Watcher metrics.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-stats.html.
+//
+type WatcherStats func(o ...func(*WatcherStatsRequest)) (*Response, error)
+
+// WatcherStatsRequest configures the Watcher Stats API request.
+//
+type WatcherStatsRequest struct {
+	Metric []string
+
+	EmitStacktraces *bool
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherStatsRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(1 + len("_watcher") + 1 + len("stats") + 1 + len(strings.Join(r.Metric, ",")))
+	path.WriteString("/")
+	path.WriteString("_watcher")
+	path.WriteString("/")
+	path.WriteString("stats")
+	if len(r.Metric) > 0 {
+		path.WriteString("/")
+		path.WriteString(strings.Join(r.Metric, ","))
+	}
+
+	params = make(map[string]string)
+
+	if r.EmitStacktraces != nil {
+		params["emit_stacktraces"] = strconv.FormatBool(*r.EmitStacktraces)
+	}
+
+	if len(r.Metric) > 0 {
+		params["metric"] = strings.Join(r.Metric, ",")
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherStats) WithContext(v context.Context) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMetric - controls what additional stat metrics should be include in the response.
+//
+func (f WatcherStats) WithMetric(v ...string) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.Metric = v
+	}
+}
+
+// WithEmitStacktraces - emits stack traces of currently running watches.
+//
+func (f WatcherStats) WithEmitStacktraces(v bool) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.EmitStacktraces = &v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherStats) WithPretty() func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherStats) WithHuman() func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherStats) WithErrorTrace() func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherStats) WithFilterPath(v ...string) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherStats) WithHeader(h map[string]string) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherStats) WithOpaqueID(s string) func(*WatcherStatsRequest) {
+	return func(r *WatcherStatsRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.watcher.stop.go b/esapi/api.xpack.watcher.stop.go
new file mode 100644
index 0000000000..85cd8cfd78
--- /dev/null
+++ b/esapi/api.xpack.watcher.stop.go
@@ -0,0 +1,196 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+)
+
+func newWatcherStopFunc(t Transport) WatcherStop {
+	return func(o ...func(*WatcherStopRequest)) (*Response, error) {
+		var r = WatcherStopRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// WatcherStop - Stops Watcher if it is running.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-stop.html.
+//
+type WatcherStop func(o ...func(*WatcherStopRequest)) (*Response, error)
+
+// WatcherStopRequest configures the Watcher Stop API request.
+//
+type WatcherStopRequest struct {
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r WatcherStopRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "POST"
+
+	path.Grow(len("/_watcher/_stop"))
+	path.WriteString("/_watcher/_stop")
+
+	params = make(map[string]string)
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f WatcherStop) WithContext(v context.Context) func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		r.ctx = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f WatcherStop) WithPretty() func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f WatcherStop) WithHuman() func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f WatcherStop) WithErrorTrace() func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f WatcherStop) WithFilterPath(v ...string) func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f WatcherStop) WithHeader(h map[string]string) func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f WatcherStop) WithOpaqueID(s string) func(*WatcherStopRequest) {
+	return func(r *WatcherStopRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.xpack.info.go b/esapi/api.xpack.xpack.info.go
new file mode 100644
index 0000000000..db2f92ef2e
--- /dev/null
+++ b/esapi/api.xpack.xpack.info.go
@@ -0,0 +1,224 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strconv"
+	"strings"
+)
+
+func newXPackInfoFunc(t Transport) XPackInfo {
+	return func(o ...func(*XPackInfoRequest)) (*Response, error) {
+		var r = XPackInfoRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// XPackInfo - Retrieves information about the installed X-Pack features.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/info-api.html.
+//
+type XPackInfo func(o ...func(*XPackInfoRequest)) (*Response, error)
+
+// XPackInfoRequest configures the X Pack Info API request.
+//
+type XPackInfoRequest struct {
+	AcceptEnterprise *bool
+	Categories       []string
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r XPackInfoRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_xpack"))
+	path.WriteString("/_xpack")
+
+	params = make(map[string]string)
+
+	if r.AcceptEnterprise != nil {
+		params["accept_enterprise"] = strconv.FormatBool(*r.AcceptEnterprise)
+	}
+
+	if len(r.Categories) > 0 {
+		params["categories"] = strings.Join(r.Categories, ",")
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f XPackInfo) WithContext(v context.Context) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.ctx = v
+	}
+}
+
+// WithAcceptEnterprise - if an enterprise license is installed, return the type and mode as 'enterprise' (default: false).
+//
+func (f XPackInfo) WithAcceptEnterprise(v bool) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.AcceptEnterprise = &v
+	}
+}
+
+// WithCategories - comma-separated list of info categories. can be any of: build, license, features.
+//
+func (f XPackInfo) WithCategories(v ...string) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.Categories = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f XPackInfo) WithPretty() func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f XPackInfo) WithHuman() func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f XPackInfo) WithErrorTrace() func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f XPackInfo) WithFilterPath(v ...string) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f XPackInfo) WithHeader(h map[string]string) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f XPackInfo) WithOpaqueID(s string) func(*XPackInfoRequest) {
+	return func(r *XPackInfoRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/api.xpack.xpack.usage.go b/esapi/api.xpack.xpack.usage.go
new file mode 100644
index 0000000000..38faa9af1d
--- /dev/null
+++ b/esapi/api.xpack.xpack.usage.go
@@ -0,0 +1,211 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Code generated from specification version 7.16.0: DO NOT EDIT
+
+package esapi
+
+import (
+	"context"
+	"net/http"
+	"strings"
+	"time"
+)
+
+func newXPackUsageFunc(t Transport) XPackUsage {
+	return func(o ...func(*XPackUsageRequest)) (*Response, error) {
+		var r = XPackUsageRequest{}
+		for _, f := range o {
+			f(&r)
+		}
+		return r.Do(r.ctx, t)
+	}
+}
+
+// ----- API Definition -------------------------------------------------------
+
+// XPackUsage - Retrieves usage information about the installed X-Pack features.
+//
+// See full documentation at https://www.elastic.co/guide/en/elasticsearch/reference/current/usage-api.html.
+//
+type XPackUsage func(o ...func(*XPackUsageRequest)) (*Response, error)
+
+// XPackUsageRequest configures the X Pack Usage API request.
+//
+type XPackUsageRequest struct {
+	MasterTimeout time.Duration
+
+	Pretty     bool
+	Human      bool
+	ErrorTrace bool
+	FilterPath []string
+
+	Header http.Header
+
+	ctx context.Context
+}
+
+// Do executes the request and returns response or error.
+//
+func (r XPackUsageRequest) Do(ctx context.Context, transport Transport) (*Response, error) {
+	var (
+		method string
+		path   strings.Builder
+		params map[string]string
+	)
+
+	method = "GET"
+
+	path.Grow(len("/_xpack/usage"))
+	path.WriteString("/_xpack/usage")
+
+	params = make(map[string]string)
+
+	if r.MasterTimeout != 0 {
+		params["master_timeout"] = formatDuration(r.MasterTimeout)
+	}
+
+	if r.Pretty {
+		params["pretty"] = "true"
+	}
+
+	if r.Human {
+		params["human"] = "true"
+	}
+
+	if r.ErrorTrace {
+		params["error_trace"] = "true"
+	}
+
+	if len(r.FilterPath) > 0 {
+		params["filter_path"] = strings.Join(r.FilterPath, ",")
+	}
+
+	req, err := newRequest(method, path.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(params) > 0 {
+		q := req.URL.Query()
+		for k, v := range params {
+			q.Set(k, v)
+		}
+		req.URL.RawQuery = q.Encode()
+	}
+
+	if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}
+
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+
+	res, err := transport.Perform(req)
+	if err != nil {
+		return nil, err
+	}
+
+	response := Response{
+		StatusCode: res.StatusCode,
+		Body:       res.Body,
+		Header:     res.Header,
+	}
+
+	return &response, nil
+}
+
+// WithContext sets the request context.
+//
+func (f XPackUsage) WithContext(v context.Context) func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.ctx = v
+	}
+}
+
+// WithMasterTimeout - specify timeout for watch write operation.
+//
+func (f XPackUsage) WithMasterTimeout(v time.Duration) func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.MasterTimeout = v
+	}
+}
+
+// WithPretty makes the response body pretty-printed.
+//
+func (f XPackUsage) WithPretty() func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.Pretty = true
+	}
+}
+
+// WithHuman makes statistical values human-readable.
+//
+func (f XPackUsage) WithHuman() func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.Human = true
+	}
+}
+
+// WithErrorTrace includes the stack trace for errors in the response body.
+//
+func (f XPackUsage) WithErrorTrace() func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.ErrorTrace = true
+	}
+}
+
+// WithFilterPath filters the properties of the response body.
+//
+func (f XPackUsage) WithFilterPath(v ...string) func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		r.FilterPath = v
+	}
+}
+
+// WithHeader adds the headers to the HTTP request.
+//
+func (f XPackUsage) WithHeader(h map[string]string) func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f XPackUsage) WithOpaqueID(s string) func(*XPackUsageRequest) {
+	return func(r *XPackUsageRequest) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
diff --git a/esapi/doc.go b/esapi/doc.go
old mode 100755
new mode 100644
index 20a976adaf..404d6bca92
--- a/esapi/doc.go
+++ b/esapi/doc.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 /*
 Package esapi provides the Go API for Elasticsearch.
 
@@ -59,8 +76,8 @@ See the documentation for each API function or struct at
 https://godoc.org/github.com/elastic/go-elasticsearch,
 or locally by:
 
-	go doc github.com/elastic/go-elasticsearch/esapi Index
-	go doc github.com/elastic/go-elasticsearch/esapi IndexRequest
+	go doc github.com/elastic/go-elasticsearch/v7/esapi Index
+	go doc github.com/elastic/go-elasticsearch/v7/esapi IndexRequest
 
 Response
 
@@ -85,10 +102,11 @@ about the API endpoints and parameters.
 The Go API is generated from the Elasticsearch JSON specification at
 https://github.com/elastic/elasticsearch/tree/master/rest-api-spec/src/main/resources/rest-api-spec/api
 by the internal package available at
-https://github.com/elastic/go-elasticsearch/tree/master/internal/cmd/generate/commands.
+https://github.com/elastic/go-elasticsearch/tree/master/internal/cmd/generate/commands/gensource.
 
 The API is tested by integration tests common to all Elasticsearch official clients, generated from the
-source at https://github.com/elastic/elasticsearch/tree/master/rest-api-spec/src/main/resources/rest-api-spec/test. The generator is provided by the internal package internal/cmd/generate.
+source at https://github.com/elastic/elasticsearch/tree/master/rest-api-spec/src/main/resources/rest-api-spec/test.
+The generator is provided by the internal package available at internal/cmd/generate/commands/gentests.
 
 */
 package esapi
diff --git a/esapi/esapi.go b/esapi/esapi.go
old mode 100755
new mode 100644
index 9c97901ce9..2efb1c2f9e
--- a/esapi/esapi.go
+++ b/esapi/esapi.go
@@ -1,11 +1,28 @@
-package esapi // import "github.com/elastic/go-elasticsearch/esapi"
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package esapi
 
 import (
 	"net/http"
 	"strconv"
 	"time"
 
-	"github.com/elastic/go-elasticsearch/internal/version"
+	"github.com/elastic/go-elasticsearch/v7/internal/version"
 )
 
 // Version returns the package version as a string.
diff --git a/esapi/esapi.request.go b/esapi/esapi.request.go
old mode 100755
new mode 100644
index 79b332eb3e..234983615e
--- a/esapi/esapi.request.go
+++ b/esapi/esapi.request.go
@@ -1,13 +1,26 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package esapi
 
 import (
-	"bytes"
 	"context"
 	"io"
-	"io/ioutil"
 	"net/http"
-	"net/url"
-	"strings"
 )
 
 const (
@@ -27,28 +40,5 @@ type Request interface {
 // newRequest creates an HTTP request.
 //
 func newRequest(method, path string, body io.Reader) (*http.Request, error) {
-	r := http.Request{
-		Method:     method,
-		URL:        &url.URL{Path: path},
-		Proto:      "HTTP/1.1",
-		ProtoMajor: 1,
-		ProtoMinor: 1,
-		Header:     make(http.Header),
-	}
-
-	if body != nil {
-		switch b := body.(type) {
-		case *bytes.Buffer:
-			r.Body = ioutil.NopCloser(body)
-			r.ContentLength = int64(b.Len())
-		case *bytes.Reader:
-			r.Body = ioutil.NopCloser(body)
-			r.ContentLength = int64(b.Len())
-		case *strings.Reader:
-			r.Body = ioutil.NopCloser(body)
-			r.ContentLength = int64(b.Len())
-		}
-	}
-
-	return &r, nil
+	return http.NewRequest(method, path, body)
 }
diff --git a/esapi/esapi.response.go b/esapi/esapi.response.go
old mode 100755
new mode 100644
index dae6785bfc..a657b5ee9e
--- a/esapi/esapi.response.go
+++ b/esapi/esapi.response.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package esapi
 
 import (
@@ -27,20 +44,32 @@ func (r *Response) String() string {
 		out = new(bytes.Buffer)
 		b1  = bytes.NewBuffer([]byte{})
 		b2  = bytes.NewBuffer([]byte{})
-		tr  = io.TeeReader(r.Body, b1)
+		tr  io.Reader
 	)
 
-	defer r.Body.Close()
+	if r != nil && r.Body != nil {
+		tr = io.TeeReader(r.Body, b1)
+		defer r.Body.Close()
 
-	if _, err := io.Copy(b2, tr); err != nil {
-		out.WriteString(fmt.Sprintf("<error reading response body: %v>", err))
-		return out.String()
+		if _, err := io.Copy(b2, tr); err != nil {
+			out.WriteString(fmt.Sprintf("<error reading response body: %v>", err))
+			return out.String()
+		}
+		defer func() { r.Body = ioutil.NopCloser(b1) }()
 	}
-	defer func() { r.Body = ioutil.NopCloser(b1) }()
 
-	out.WriteString(fmt.Sprintf("[%d %s]", r.StatusCode, http.StatusText(r.StatusCode)))
-	out.WriteRune(' ')
-	out.ReadFrom(b2) // errcheck exclude (*bytes.Buffer).ReadFrom
+	if r != nil {
+		out.WriteString(fmt.Sprintf("[%d %s]", r.StatusCode, http.StatusText(r.StatusCode)))
+		if r.StatusCode > 0 {
+			out.WriteRune(' ')
+		}
+	} else {
+		out.WriteString("[0 <nil>]")
+	}
+
+	if r != nil && r.Body != nil {
+		out.ReadFrom(b2) // errcheck exclude (*bytes.Buffer).ReadFrom
+	}
 
 	return out.String()
 }
@@ -49,9 +78,11 @@ func (r *Response) String() string {
 //
 func (r *Response) Status() string {
 	var b strings.Builder
-	b.WriteString(strconv.Itoa(r.StatusCode))
-	b.WriteString(" ")
-	b.WriteString(http.StatusText(r.StatusCode))
+	if r != nil {
+		b.WriteString(strconv.Itoa(r.StatusCode))
+		b.WriteString(" ")
+		b.WriteString(http.StatusText(r.StatusCode))
+	}
 	return b.String()
 }
 
@@ -60,3 +91,15 @@ func (r *Response) Status() string {
 func (r *Response) IsError() bool {
 	return r.StatusCode > 299
 }
+
+// Warnings returns the deprecation warnings from response headers.
+//
+func (r *Response) Warnings() []string {
+	return r.Header["Warning"]
+}
+
+// HasWarnings returns true when the response headers contain deprecation warnings.
+//
+func (r *Response) HasWarnings() bool {
+	return len(r.Warnings()) > 0
+}
diff --git a/esapi/esapi.response_example_test.go b/esapi/esapi.response_example_test.go
old mode 100755
new mode 100644
index 44f796ff0d..2edd8cab00
--- a/esapi/esapi.response_example_test.go
+++ b/esapi/esapi.response_example_test.go
@@ -1,9 +1,26 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package esapi_test
 
 import (
 	"log"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
 )
 
 func ExampleResponse_IsError() {
diff --git a/esapi/esapi_benchmark_test.go b/esapi/esapi_benchmark_test.go
old mode 100755
new mode 100644
index 53db966d3e..88e0c30e34
--- a/esapi/esapi_benchmark_test.go
+++ b/esapi/esapi_benchmark_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package esapi_test
 
 import (
@@ -8,17 +25,29 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 // TODO(karmi): Refactor into a shared mock/testing package
 
 var (
-	defaultResponse    = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader("MOCK"))}
+	defaultResponse    = &http.Response{
+		StatusCode: 200,
+		Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
+		Body: ioutil.NopCloser(strings.NewReader("MOCK")),
+	}
 	defaultRoundTripFn = func(*http.Request) (*http.Response, error) { return defaultResponse, nil }
-	errorRoundTripFn   = func(*http.Request) (*http.Response, error) {
+	errorRoundTripFn   = func(request *http.Request) (*http.Response, error) {
+		if request.URL.Path == "/" {
+			return &http.Response{
+				StatusCode: 200,
+				Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
+				Body: ioutil.NopCloser(strings.NewReader("{}")),
+			}, nil
+		}
 		return &http.Response{
+			Header: http.Header{"X-Elastic-Product": []string{"Elasticsearch"}},
 			StatusCode: 400,
 			Body: ioutil.NopCloser(strings.NewReader(`
 					{ "error" : {
diff --git a/esapi/esapi_integration_test.go b/esapi/esapi_integration_test.go
index cccae7834e..be6c36b9ba 100644
--- a/esapi/esapi_integration_test.go
+++ b/esapi/esapi_integration_test.go
@@ -1,14 +1,34 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build integration
 
 package esapi_test
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
+	"strings"
 	"testing"
 	"time"
 
-	"github.com/elastic/go-elasticsearch"
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
 )
 
 func TestAPI(t *testing.T) {
@@ -18,6 +38,7 @@ func TestAPI(t *testing.T) {
 			t.Fatalf("Error creating the client: %s\n", err)
 		}
 
+		es.Cluster.Health(es.Cluster.Health.WithWaitForStatus("yellow"))
 		res, err := es.Search(es.Search.WithTimeout(500 * time.Millisecond))
 		if err != nil {
 			t.Fatalf("Error getting the response: %s\n", err)
@@ -35,4 +56,154 @@ func TestAPI(t *testing.T) {
 		}
 		fmt.Printf("took=%vms\n", d["took"])
 	})
+
+	t.Run("Headers", func(t *testing.T) {
+		es, err := elasticsearch.NewDefaultClient()
+		if err != nil {
+			t.Fatalf("Error creating the client: %s\n", err)
+		}
+
+		res, err := es.Info(es.Info.WithHeader(map[string]string{"Accept": "application/yaml"}))
+		if err != nil {
+			t.Fatalf("Error getting the response: %s\n", err)
+		}
+		defer res.Body.Close()
+
+		if res.IsError() {
+			t.Fatalf("Error response: %s", res.String())
+		}
+
+		if !strings.HasPrefix(res.String(), "[200 OK] ---") {
+			t.Errorf("Unexpected response body: doesn't start with '[200 OK] ---'; %s", res.String())
+		}
+	})
+
+	t.Run("OpaqueID", func(t *testing.T) {
+		var (
+			buf bytes.Buffer
+
+			res *esapi.Response
+			err error
+
+			requestID = "reindex-123"
+		)
+
+		es, err := elasticsearch.NewDefaultClient()
+		if err != nil {
+			t.Fatalf("Error creating the client: %s\n", err)
+		}
+
+		// Prepare indices
+		//
+		es.Indices.Delete([]string{"test", "reindexed"}, es.Indices.Delete.WithIgnoreUnavailable(true))
+
+		// Index data
+		//
+		for j := 1; j <= 1000; j++ {
+			meta := []byte(fmt.Sprintf(`{ "index" : { "_id" : "%d" } }%s`, j, "\n"))
+			data := []byte(`{"content":"` + strings.Repeat("ABC", 100) + `"}`)
+			data = append(data, "\n"...)
+
+			buf.Grow(len(meta) + len(data))
+			buf.Write(meta)
+			buf.Write(data)
+		}
+		res, err = es.Bulk(bytes.NewReader(buf.Bytes()), es.Bulk.WithIndex("test"), es.Bulk.WithRefresh("true"))
+		if err != nil {
+			t.Fatalf("Failed to index data: %s", err)
+		}
+		res.Body.Close()
+		if res.IsError() {
+			t.Fatalf("Failed to index data: %s", res.Status())
+		}
+
+		// Launch reindexing task with wait_for_completion=false
+		//
+		res, err = es.Reindex(
+			strings.NewReader(`{"source":{"index":"test"}, "dest": {"index":"reindexed"}}`),
+			es.Reindex.WithWaitForCompletion(false),
+			es.Reindex.WithRequestsPerSecond(1),
+			es.Reindex.WithOpaqueID(requestID))
+		if err != nil {
+			t.Fatalf("Failed to reindex: %s", err)
+		}
+		if res.IsError() {
+			t.Fatalf("Failed to reindex: %s", res.Status())
+		}
+		time.Sleep(10 * time.Millisecond)
+
+		res, err = es.Tasks.List(es.Tasks.List.WithPretty())
+		if err != nil {
+			t.Fatalf("ERROR: %s", err)
+		}
+		res.Body.Close()
+		if res.IsError() {
+			t.Fatalf("Failed to get tasks: %s", res.Status())
+		}
+
+		// Get the list of tasks
+		//
+		res, err = es.Tasks.List(es.Tasks.List.WithPretty())
+		if err != nil {
+			t.Fatalf("ERROR: %s", err)
+		}
+		defer res.Body.Close()
+
+		if res.IsError() {
+			t.Fatalf("Failed to get tasks: %s", res.Status())
+		}
+
+		type task struct {
+			Node        string
+			ID          int
+			Action      string
+			RunningTime time.Duration `json:"running_time_in_nanos"`
+			Cancellable bool
+			Headers     map[string]interface{}
+		}
+
+		type node struct {
+			Tasks map[string]task
+		}
+
+		var nodes map[string]map[string]node
+		if err := json.NewDecoder(res.Body).Decode(&nodes); err != nil {
+			t.Fatalf("Failed to decode response: %s", err)
+		}
+
+		var hasReindexTask bool
+
+		for _, n := range nodes["nodes"] {
+			for taskID, task := range n.Tasks {
+				if task.Headers["X-Opaque-Id"] == requestID {
+					if strings.Contains(task.Action, "reindex") {
+						hasReindexTask = true
+					}
+					fmt.Printf("* %s, %s | %s (%s)\n", requestID, taskID, task.Action, task.RunningTime)
+				}
+			}
+		}
+
+		if !hasReindexTask {
+			t.Errorf("Expected reindex task in %+v", nodes["nodes"])
+		}
+
+		for _, n := range nodes["nodes"] {
+			for taskID, task := range n.Tasks {
+				if task.Headers["X-Opaque-Id"] == requestID {
+					if task.Cancellable {
+						fmt.Printf("=> Closing task %s\n", taskID)
+						res, err = es.Tasks.Cancel(es.Tasks.Cancel.WithTaskID(taskID))
+						if err != nil {
+							t.Fatalf("ERROR: %s", err)
+						}
+						res.Body.Close()
+						if res.IsError() {
+							t.Fatalf("Failed to cancel task: %s", res)
+						}
+					}
+				}
+			}
+		}
+	})
 }
diff --git a/esapi/esapi_internal_test.go b/esapi/esapi_internal_test.go
old mode 100755
new mode 100644
index 08864dc7d3..4e2f92380b
--- a/esapi/esapi_internal_test.go
+++ b/esapi/esapi_internal_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package esapi
diff --git a/esapi/esapi_request_internal_test.go b/esapi/esapi_request_internal_test.go
old mode 100755
new mode 100644
index e42b0806da..2a6e59f83d
--- a/esapi/esapi_request_internal_test.go
+++ b/esapi/esapi_request_internal_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package esapi
diff --git a/esapi/esapi_response_internal_test.go b/esapi/esapi_response_internal_test.go
old mode 100755
new mode 100644
index 4819b639f9..baafcb0133
--- a/esapi/esapi_response_internal_test.go
+++ b/esapi/esapi_response_internal_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package esapi
@@ -5,6 +22,7 @@ package esapi
 import (
 	"errors"
 	"io/ioutil"
+	"net/http"
 	"strings"
 	"testing"
 )
@@ -16,13 +34,13 @@ func (errReader) Read(p []byte) (n int, err error) { return 1, errors.New("MOCK
 func TestAPIResponse(t *testing.T) {
 	var (
 		body string
-		res  Response
+		res  *Response
 	)
 
 	t.Run("String", func(t *testing.T) {
 		body = `{"foo":"bar"}`
 
-		res = Response{StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader(body))}
+		res = &Response{StatusCode: 200, Body: ioutil.NopCloser(strings.NewReader(body))}
 
 		expected := `[200 OK]` + ` ` + body
 		if res.String() != expected {
@@ -30,11 +48,24 @@ func TestAPIResponse(t *testing.T) {
 		}
 	})
 
-	t.Run("String Error", func(t *testing.T) {
-		res = Response{StatusCode: 200, Body: ioutil.NopCloser(errReader{})}
+	t.Run("String with empty response", func(t *testing.T) {
+		res = &Response{}
+
+		if res.String() != "[0 ]" {
+			t.Errorf("Unexpected response: %s", res.String())
+		}
+	})
+
+	t.Run("String with nil response", func(t *testing.T) {
+		res = nil
+
+		if res.String() != "[0 <nil>]" {
+			t.Errorf("Unexpected response: %s", res.String())
+		}
+	})
 
-		t.Log(res.String())
-		t.Log(res.String())
+	t.Run("String Error", func(t *testing.T) {
+		res = &Response{StatusCode: 200, Body: ioutil.NopCloser(errReader{})}
 
 		if !strings.Contains(res.String(), `error reading response`) {
 			t.Errorf("Expected response string to contain 'error reading response', got: %s", res.String())
@@ -42,7 +73,7 @@ func TestAPIResponse(t *testing.T) {
 	})
 
 	t.Run("Status", func(t *testing.T) {
-		res = Response{StatusCode: 404}
+		res = &Response{StatusCode: 404}
 
 		if res.Status() != `404 Not Found` {
 			t.Errorf("Unexpected response status text: %s, want: 404 Not Found", res.Status())
@@ -50,16 +81,31 @@ func TestAPIResponse(t *testing.T) {
 	})
 
 	t.Run("IsError", func(t *testing.T) {
-		res = Response{StatusCode: 201}
+		res = &Response{StatusCode: 201}
 
 		if res.IsError() {
 			t.Errorf("Unexpected error for response: %s", res.Status())
 		}
 
-		res = Response{StatusCode: 403}
+		res = &Response{StatusCode: 403}
 
 		if !res.IsError() {
 			t.Errorf("Expected error for response: %s", res.Status())
 		}
 	})
+
+	t.Run("Warnings", func(t *testing.T) {
+		hdr := http.Header{}
+		hdr.Add("Warning", "Foo 1")
+		hdr.Add("Warning", "Foo 2")
+		res = &Response{StatusCode: 201, Header: hdr}
+
+		if !res.HasWarnings() {
+			t.Errorf("Expected response to have warnings")
+		}
+
+		if len(res.Warnings()) != 2 {
+			t.Errorf("Expected [2] warnings, got: %d", len(res.Warnings()))
+		}
+	})
 }
diff --git a/esapi/test/.gitignore b/esapi/test/.gitignore
old mode 100755
new mode 100644
diff --git a/esapi/test/go.mod b/esapi/test/go.mod
index 2153e69526..661cfb9b2f 100644
--- a/esapi/test/go.mod
+++ b/esapi/test/go.mod
@@ -1,11 +1,11 @@
-module github.com/elastic/go-elasticsearch/esapi/test
+module github.com/elastic/go-elasticsearch/v7/esapi/test
 
 go 1.11
 
-replace github.com/elastic/go-elasticsearch => ../../
+replace github.com/elastic/go-elasticsearch/v7 => ../../
 
 require (
-	github.com/elastic/go-elasticsearch master
+	github.com/elastic/go-elasticsearch/v7 7.x
 
 	gopkg.in/yaml.v2 v2.2.2
 )
diff --git a/estransport/connection.go b/estransport/connection.go
new file mode 100644
index 0000000000..53eb081b54
--- /dev/null
+++ b/estransport/connection.go
@@ -0,0 +1,329 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"net/url"
+	"sort"
+	"sync"
+	"time"
+)
+
+var (
+	defaultResurrectTimeoutInitial      = 60 * time.Second
+	defaultResurrectTimeoutFactorCutoff = 5
+)
+
+// Selector defines the interface for selecting connections from the pool.
+//
+type Selector interface {
+	Select([]*Connection) (*Connection, error)
+}
+
+// ConnectionPool defines the interface for the connection pool.
+//
+type ConnectionPool interface {
+	Next() (*Connection, error)  // Next returns the next available connection.
+	OnSuccess(*Connection) error // OnSuccess reports that the connection was successful.
+	OnFailure(*Connection) error // OnFailure reports that the connection failed.
+	URLs() []*url.URL            // URLs returns the list of URLs of available connections.
+}
+
+// Connection represents a connection to a node.
+//
+type Connection struct {
+	sync.Mutex
+
+	URL       *url.URL
+	IsDead    bool
+	DeadSince time.Time
+	Failures  int
+
+	ID         string
+	Name       string
+	Roles      []string
+	Attributes map[string]interface{}
+}
+
+type singleConnectionPool struct {
+	connection *Connection
+
+	metrics *metrics
+}
+
+type statusConnectionPool struct {
+	sync.Mutex
+
+	live     []*Connection // List of live connections
+	dead     []*Connection // List of dead connections
+	selector Selector
+
+	metrics *metrics
+}
+
+type roundRobinSelector struct {
+	sync.Mutex
+
+	curr int // Index of the current connection
+}
+
+// NewConnectionPool creates and returns a default connection pool.
+//
+func NewConnectionPool(conns []*Connection, selector Selector) (ConnectionPool, error) {
+	if len(conns) == 1 {
+		return &singleConnectionPool{connection: conns[0]}, nil
+	}
+	if selector == nil {
+		selector = &roundRobinSelector{curr: -1}
+	}
+	return &statusConnectionPool{live: conns, selector: selector}, nil
+}
+
+// Next returns the connection from pool.
+//
+func (cp *singleConnectionPool) Next() (*Connection, error) {
+	return cp.connection, nil
+}
+
+// OnSuccess is a no-op for single connection pool.
+func (cp *singleConnectionPool) OnSuccess(c *Connection) error { return nil }
+
+// OnFailure is a no-op for single connection pool.
+func (cp *singleConnectionPool) OnFailure(c *Connection) error { return nil }
+
+// URLs returns the list of URLs of available connections.
+func (cp *singleConnectionPool) URLs() []*url.URL { return []*url.URL{cp.connection.URL} }
+
+func (cp *singleConnectionPool) connections() []*Connection { return []*Connection{cp.connection} }
+
+// Next returns a connection from pool, or an error.
+//
+func (cp *statusConnectionPool) Next() (*Connection, error) {
+	cp.Lock()
+	defer cp.Unlock()
+
+	// Return next live connection
+	if len(cp.live) > 0 {
+		return cp.selector.Select(cp.live)
+	} else if len(cp.dead) > 0 {
+		// No live connection is available, resurrect one of the dead ones.
+		c := cp.dead[len(cp.dead)-1]
+		cp.dead = cp.dead[:len(cp.dead)-1]
+		c.Lock()
+		defer c.Unlock()
+		cp.resurrect(c, false)
+		return c, nil
+	}
+	return nil, errors.New("no connection available")
+}
+
+// OnSuccess marks the connection as successful.
+//
+func (cp *statusConnectionPool) OnSuccess(c *Connection) error {
+	c.Lock()
+	defer c.Unlock()
+
+	// Short-circuit for live connection
+	if !c.IsDead {
+		return nil
+	}
+
+	c.markAsHealthy()
+
+	cp.Lock()
+	defer cp.Unlock()
+	return cp.resurrect(c, true)
+}
+
+// OnFailure marks the connection as failed.
+//
+func (cp *statusConnectionPool) OnFailure(c *Connection) error {
+	cp.Lock()
+	defer cp.Unlock()
+
+	c.Lock()
+
+	if c.IsDead {
+		if debugLogger != nil {
+			debugLogger.Logf("Already removed %s\n", c.URL)
+		}
+		c.Unlock()
+		return nil
+	}
+
+	if debugLogger != nil {
+		debugLogger.Logf("Removing %s...\n", c.URL)
+	}
+	c.markAsDead()
+	cp.scheduleResurrect(c)
+	c.Unlock()
+
+	// Push item to dead list and sort slice by number of failures
+	cp.dead = append(cp.dead, c)
+	sort.Slice(cp.dead, func(i, j int) bool {
+		c1 := cp.dead[i]
+		c2 := cp.dead[j]
+		c1.Lock()
+		c2.Lock()
+		defer c1.Unlock()
+		defer c2.Unlock()
+
+		res := c1.Failures > c2.Failures
+		return res
+	})
+
+	// Check if connection exists in the list, return error if not.
+	index := -1
+	for i, conn := range cp.live {
+		if conn == c {
+			index = i
+		}
+	}
+	if index < 0 {
+		return errors.New("connection not in live list")
+	}
+
+	// Remove item; https://github.com/golang/go/wiki/SliceTricks
+	copy(cp.live[index:], cp.live[index+1:])
+	cp.live = cp.live[:len(cp.live)-1]
+
+	return nil
+}
+
+// URLs returns the list of URLs of available connections.
+//
+func (cp *statusConnectionPool) URLs() []*url.URL {
+	var urls []*url.URL
+
+	cp.Lock()
+	defer cp.Unlock()
+
+	for _, c := range cp.live {
+		urls = append(urls, c.URL)
+	}
+
+	return urls
+}
+
+func (cp *statusConnectionPool) connections() []*Connection {
+	var conns []*Connection
+	conns = append(conns, cp.live...)
+	conns = append(conns, cp.dead...)
+	return conns
+}
+
+// resurrect adds the connection to the list of available connections.
+// When removeDead is true, it also removes it from the dead list.
+// The calling code is responsible for locking.
+//
+func (cp *statusConnectionPool) resurrect(c *Connection, removeDead bool) error {
+	if debugLogger != nil {
+		debugLogger.Logf("Resurrecting %s\n", c.URL)
+	}
+
+	c.markAsLive()
+	cp.live = append(cp.live, c)
+
+	if removeDead {
+		index := -1
+		for i, conn := range cp.dead {
+			if conn == c {
+				index = i
+			}
+		}
+		if index >= 0 {
+			// Remove item; https://github.com/golang/go/wiki/SliceTricks
+			copy(cp.dead[index:], cp.dead[index+1:])
+			cp.dead = cp.dead[:len(cp.dead)-1]
+		}
+	}
+
+	return nil
+}
+
+// scheduleResurrect schedules the connection to be resurrected.
+//
+func (cp *statusConnectionPool) scheduleResurrect(c *Connection) {
+	factor := math.Min(float64(c.Failures-1), float64(defaultResurrectTimeoutFactorCutoff))
+	timeout := time.Duration(defaultResurrectTimeoutInitial.Seconds() * math.Exp2(factor) * float64(time.Second))
+	if debugLogger != nil {
+		debugLogger.Logf("Resurrect %s (failures=%d, factor=%1.1f, timeout=%s) in %s\n", c.URL, c.Failures, factor, timeout, c.DeadSince.Add(timeout).Sub(time.Now().UTC()).Truncate(time.Second))
+	}
+
+	time.AfterFunc(timeout, func() {
+		cp.Lock()
+		defer cp.Unlock()
+
+		c.Lock()
+		defer c.Unlock()
+
+		if !c.IsDead {
+			if debugLogger != nil {
+				debugLogger.Logf("Already resurrected %s\n", c.URL)
+			}
+			return
+		}
+
+		cp.resurrect(c, true)
+	})
+}
+
+// Select returns the connection in a round-robin fashion.
+//
+func (s *roundRobinSelector) Select(conns []*Connection) (*Connection, error) {
+	s.Lock()
+	defer s.Unlock()
+
+	s.curr = (s.curr + 1) % len(conns)
+	return conns[s.curr], nil
+}
+
+// markAsDead marks the connection as dead.
+//
+func (c *Connection) markAsDead() {
+	c.IsDead = true
+	if c.DeadSince.IsZero() {
+		c.DeadSince = time.Now().UTC()
+	}
+	c.Failures++
+}
+
+// markAsLive marks the connection as alive.
+//
+func (c *Connection) markAsLive() {
+	c.IsDead = false
+}
+
+// markAsHealthy marks the connection as healthy.
+//
+func (c *Connection) markAsHealthy() {
+	c.IsDead = false
+	c.DeadSince = time.Time{}
+	c.Failures = 0
+}
+
+// String returns a readable connection representation.
+//
+func (c *Connection) String() string {
+	c.Lock()
+	defer c.Unlock()
+	return fmt.Sprintf("<%s> dead=%v failures=%d", c.URL, c.IsDead, c.Failures)
+}
diff --git a/estransport/connection_benchmark_test.go b/estransport/connection_benchmark_test.go
new file mode 100644
index 0000000000..2b5c84da82
--- /dev/null
+++ b/estransport/connection_benchmark_test.go
@@ -0,0 +1,313 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package estransport
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"net/url"
+	"testing"
+
+	_ "net/http/pprof"
+)
+
+func init() {
+	go func() { log.Fatalln(http.ListenAndServe("localhost:6060", nil)) }()
+}
+
+func BenchmarkSingleConnectionPool(b *testing.B) {
+	b.ReportAllocs()
+
+	b.Run("Next()", func(b *testing.B) {
+		pool := &singleConnectionPool{connection: &Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}}}
+
+		b.Run("Single          ", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				_, err := pool.Next()
+				if err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+			}
+		})
+
+		b.Run("Parallel (1000)", func(b *testing.B) {
+			b.SetParallelism(1000)
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					_, err := pool.Next()
+					if err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+	})
+
+	b.Run("OnFailure()", func(b *testing.B) {
+		pool := &singleConnectionPool{connection: &Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}}}
+
+		b.Run("Single     ", func(b *testing.B) {
+			c, _ := pool.Next()
+
+			for i := 0; i < b.N; i++ {
+				if err := pool.OnFailure(c); err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+			}
+		})
+
+		b.Run("Parallel (1000)", func(b *testing.B) {
+			b.SetParallelism(1000)
+			b.RunParallel(func(pb *testing.PB) {
+				c, _ := pool.Next()
+
+				for pb.Next() {
+					if err := pool.OnFailure(c); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+	})
+}
+
+func BenchmarkStatusConnectionPool(b *testing.B) {
+	b.ReportAllocs()
+
+	var conns []*Connection
+	for i := 0; i < 1000; i++ {
+		conns = append(conns, &Connection{URL: &url.URL{Scheme: "http", Host: fmt.Sprintf("foo%d", i)}})
+	}
+
+	b.Run("Next()", func(b *testing.B) {
+		pool := &statusConnectionPool{
+			live:     conns,
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		b.Run("Single     ", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				_, err := pool.Next()
+				if err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+			}
+		})
+
+		b.Run("Parallel (100)", func(b *testing.B) {
+			b.SetParallelism(100)
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					_, err := pool.Next()
+					if err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+
+		b.Run("Parallel (1000)", func(b *testing.B) {
+			b.SetParallelism(1000)
+			b.RunParallel(func(pb *testing.PB) {
+				for pb.Next() {
+					_, err := pool.Next()
+					if err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+	})
+
+	b.Run("OnFailure()", func(b *testing.B) {
+		pool := &statusConnectionPool{
+			live:     conns,
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		b.Run("Single     ", func(b *testing.B) {
+			c, err := pool.Next()
+			if err != nil {
+				b.Fatalf("Unexpected error: %s", err)
+			}
+
+			for i := 0; i < b.N; i++ {
+				if err := pool.OnFailure(c); err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+			}
+		})
+
+		b.Run("Parallel (10)", func(b *testing.B) {
+			b.SetParallelism(10)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					if err := pool.OnFailure(c); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+
+		b.Run("Parallel (100)", func(b *testing.B) {
+			b.SetParallelism(100)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					if err := pool.OnFailure(c); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+	})
+
+	b.Run("OnSuccess()", func(b *testing.B) {
+		pool := &statusConnectionPool{
+			live:     conns,
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		b.Run("Single     ", func(b *testing.B) {
+			c, err := pool.Next()
+			if err != nil {
+				b.Fatalf("Unexpected error: %s", err)
+			}
+
+			for i := 0; i < b.N; i++ {
+				if err := pool.OnSuccess(c); err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+			}
+		})
+
+		b.Run("Parallel (10)", func(b *testing.B) {
+			b.SetParallelism(10)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					if err := pool.OnSuccess(c); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+
+		b.Run("Parallel (100)", func(b *testing.B) {
+			b.SetParallelism(100)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					if err := pool.OnSuccess(c); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+				}
+			})
+		})
+	})
+
+	b.Run("resurrect()", func(b *testing.B) {
+		pool := &statusConnectionPool{
+			live:     conns,
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		b.Run("Single", func(b *testing.B) {
+			c, err := pool.Next()
+			if err != nil {
+				b.Fatalf("Unexpected error: %s", err)
+			}
+			err = pool.OnFailure(c)
+			if err != nil {
+				b.Fatalf("Unexpected error: %s", err)
+			}
+
+			for i := 0; i < b.N; i++ {
+				pool.Lock()
+				if err := pool.resurrect(c, true); err != nil {
+					b.Errorf("Unexpected error: %v", err)
+				}
+				pool.Unlock()
+			}
+		})
+
+		b.Run("Parallel (10)", func(b *testing.B) {
+			b.SetParallelism(10)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+				err = pool.OnFailure(c)
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					pool.Lock()
+					if err := pool.resurrect(c, true); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+					pool.Unlock()
+				}
+			})
+		})
+
+		b.Run("Parallel (100)", func(b *testing.B) {
+			b.SetParallelism(100)
+			b.RunParallel(func(pb *testing.PB) {
+				c, err := pool.Next()
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+				err = pool.OnFailure(c)
+				if err != nil {
+					b.Fatalf("Unexpected error: %s", err)
+				}
+
+				for pb.Next() {
+					pool.Lock()
+					if err := pool.resurrect(c, true); err != nil {
+						b.Errorf("Unexpected error: %v", err)
+					}
+					pool.Unlock()
+				}
+			})
+		})
+	})
+}
diff --git a/estransport/connection_integration_test.go b/estransport/connection_integration_test.go
new file mode 100644
index 0000000000..c745c0853a
--- /dev/null
+++ b/estransport/connection_integration_test.go
@@ -0,0 +1,163 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build integration
+
+package estransport
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"os"
+	"testing"
+	"time"
+)
+
+func NewServer(addr string, handler http.Handler) *http.Server {
+	return &http.Server{Addr: addr, Handler: handler}
+}
+
+func TestStatusConnectionPool(t *testing.T) {
+	defaultResurrectTimeoutInitial = time.Second
+	defer func() { defaultResurrectTimeoutInitial = 60 * time.Second }()
+
+	var (
+		server      *http.Server
+		servers     []*http.Server
+		serverURLs  []*url.URL
+		serverHosts []string
+		numServers  = 3
+
+		defaultHandler = func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "OK") }
+	)
+
+	for i := 1; i <= numServers; i++ {
+		s := NewServer(fmt.Sprintf("localhost:1000%d", i), http.HandlerFunc(defaultHandler))
+
+		go func(s *http.Server) {
+			if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+				t.Fatalf("Unable to start server: %s", err)
+			}
+		}(s)
+
+		defer func(s *http.Server) { s.Close() }(s)
+
+		servers = append(servers, s)
+		time.Sleep(time.Millisecond)
+	}
+
+	for _, s := range servers {
+		u, _ := url.Parse("http://" + s.Addr)
+		serverURLs = append(serverURLs, u)
+		serverHosts = append(serverHosts, u.String())
+	}
+
+	fmt.Printf("==> Started %d servers on %s\n", numServers, serverHosts)
+
+	cfg := Config{URLs: serverURLs}
+
+	if _, ok := os.LookupEnv("GITHUB_ACTIONS"); !ok {
+		cfg.Logger = &TextLogger{Output: os.Stdout}
+		cfg.EnableDebugLogger = true
+	}
+
+	transport, _ := New(cfg)
+
+	pool := transport.pool.(*statusConnectionPool)
+
+	for i := 1; i <= 9; i++ {
+		req, _ := http.NewRequest("GET", "/", nil)
+		res, err := transport.Perform(req)
+		if err != nil {
+			t.Errorf("Unexpected error: %v", err)
+		}
+		if res.StatusCode != 200 {
+			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
+		}
+	}
+
+	pool.Lock()
+	if len(pool.live) != 3 {
+		t.Errorf("Unexpected number of live connections, want=3, got=%d", len(pool.live))
+	}
+	pool.Unlock()
+
+	server = servers[1]
+	fmt.Printf("==> Closing server: %s\n", server.Addr)
+	if err := server.Close(); err != nil {
+		t.Fatalf("Unable to close server: %s", err)
+	}
+
+	for i := 1; i <= 9; i++ {
+		req, _ := http.NewRequest("GET", "/", nil)
+		res, err := transport.Perform(req)
+		if err != nil {
+			t.Errorf("Unexpected error: %v", err)
+		}
+		if res.StatusCode != 200 {
+			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
+		}
+	}
+
+	pool.Lock()
+	if len(pool.live) != 2 {
+		t.Errorf("Unexpected number of live connections, want=2, got=%d", len(pool.live))
+	}
+	pool.Unlock()
+
+	pool.Lock()
+	if len(pool.dead) != 1 {
+		t.Errorf("Unexpected number of dead connections, want=1, got=%d", len(pool.dead))
+	}
+	pool.Unlock()
+
+	server = NewServer("localhost:10002", http.HandlerFunc(defaultHandler))
+	servers[1] = server
+	fmt.Printf("==> Starting server: %s\n", server.Addr)
+	go func() {
+		if err := server.ListenAndServe(); err != nil {
+			t.Fatalf("Unable to start server: %s", err)
+		}
+	}()
+
+	fmt.Println("==> Waiting 1.25s for resurrection...")
+	time.Sleep(1250 * time.Millisecond)
+
+	for i := 1; i <= 9; i++ {
+		req, _ := http.NewRequest("GET", "/", nil)
+		res, err := transport.Perform(req)
+		if err != nil {
+			t.Errorf("Unexpected error: %v", err)
+		}
+		if res.StatusCode != 200 {
+			t.Errorf("Unexpected status code, want=200, got=%d", res.StatusCode)
+		}
+	}
+
+	pool.Lock()
+	if len(pool.live) != 3 {
+		t.Errorf("Unexpected number of live connections, want=3, got=%d", len(pool.live))
+	}
+	pool.Unlock()
+
+	pool.Lock()
+	if len(pool.dead) != 0 {
+		t.Errorf("Unexpected number of dead connections, want=0, got=%d", len(pool.dead))
+	}
+	pool.Unlock()
+}
diff --git a/estransport/connection_internal_test.go b/estransport/connection_internal_test.go
new file mode 100644
index 0000000000..8c5d9263b7
--- /dev/null
+++ b/estransport/connection_internal_test.go
@@ -0,0 +1,378 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package estransport
+
+import (
+	"net/url"
+	"regexp"
+	"testing"
+	"time"
+)
+
+func TestSingleConnectionPoolNext(t *testing.T) {
+	t.Run("Single URL", func(t *testing.T) {
+		pool := &singleConnectionPool{
+			connection: &Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+		}
+
+		for i := 0; i < 7; i++ {
+			c, err := pool.Next()
+			if err != nil {
+				t.Errorf("Unexpected error: %s", err)
+			}
+
+			if c.URL.String() != "http://foo1" {
+				t.Errorf("Unexpected URL, want=http://foo1, got=%s", c.URL)
+			}
+		}
+	})
+}
+
+func TestSingleConnectionPoolOnFailure(t *testing.T) {
+	t.Run("Noop", func(t *testing.T) {
+		pool := &singleConnectionPool{
+			connection: &Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+		}
+
+		if err := pool.OnFailure(&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}}); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+	})
+}
+
+func TestStatusConnectionPoolNext(t *testing.T) {
+	t.Run("No URL", func(t *testing.T) {
+		pool := &statusConnectionPool{}
+
+		c, err := pool.Next()
+		if err == nil {
+			t.Errorf("Expected error, but got: %s", c.URL)
+		}
+	})
+
+	t.Run("Two URLs", func(t *testing.T) {
+		var c *Connection
+
+		pool := &statusConnectionPool{
+			live: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo2"}},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		c, _ = pool.Next()
+
+		if c.URL.String() != "http://foo1" {
+			t.Errorf("Unexpected URL, want=foo1, got=%s", c.URL)
+		}
+
+		c, _ = pool.Next()
+		if c.URL.String() != "http://foo2" {
+			t.Errorf("Unexpected URL, want=http://foo2, got=%s", c.URL)
+		}
+
+		c, _ = pool.Next()
+		if c.URL.String() != "http://foo1" {
+			t.Errorf("Unexpected URL, want=http://foo1, got=%s", c.URL)
+		}
+	})
+
+	t.Run("Three URLs", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			live: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo2"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo3"}},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		var expected string
+		for i := 0; i < 11; i++ {
+			c, err := pool.Next()
+
+			if err != nil {
+				t.Errorf("Unexpected error: %s", err)
+			}
+
+			switch i % len(pool.live) {
+			case 0:
+				expected = "http://foo1"
+			case 1:
+				expected = "http://foo2"
+			case 2:
+				expected = "http://foo3"
+			default:
+				t.Fatalf("Unexpected i %% 3: %d", i%3)
+			}
+
+			if c.URL.String() != expected {
+				t.Errorf("Unexpected URL, want=%s, got=%s", expected, c.URL)
+			}
+		}
+	})
+
+	t.Run("Resurrect dead connection when no live is available", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			live: []*Connection{},
+			dead: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}, Failures: 3},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo2"}, Failures: 1},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		c, err := pool.Next()
+		if err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		if c == nil {
+			t.Errorf("Expected connection, got nil: %s", c)
+		}
+
+		if c.URL.String() != "http://foo2" {
+			t.Errorf("Expected <http://foo2>, got: %s", c.URL.String())
+		}
+
+		if c.IsDead {
+			t.Errorf("Expected connection to be live, got: %s", c)
+		}
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 connection in live list, got: %s", pool.live)
+		}
+
+		if len(pool.dead) != 1 {
+			t.Errorf("Expected 1 connection in dead list, got: %s", pool.dead)
+		}
+	})
+}
+
+func TestStatusConnectionPoolOnSuccess(t *testing.T) {
+	t.Run("Move connection to live list and mark it as healthy", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			dead: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}, Failures: 3, IsDead: true},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := pool.dead[0]
+
+		if err := pool.OnSuccess(conn); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if conn.IsDead {
+			t.Errorf("Expected the connection to be live; %s", conn)
+		}
+
+		if !conn.DeadSince.IsZero() {
+			t.Errorf("Unexpected value for DeadSince: %s", conn.DeadSince)
+		}
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 live connection, got: %d", len(pool.live))
+		}
+
+		if len(pool.dead) != 0 {
+			t.Errorf("Expected 0 dead connections, got: %d", len(pool.dead))
+		}
+	})
+}
+
+func TestStatusConnectionPoolOnFailure(t *testing.T) {
+	t.Run("Remove connection, mark it, and sort dead connections", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			live: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo2"}},
+			},
+			dead: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo3"}, Failures: 0},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo4"}, Failures: 99},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := pool.live[0]
+
+		if err := pool.OnFailure(conn); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if !conn.IsDead {
+			t.Errorf("Expected the connection to be dead; %s", conn)
+		}
+
+		if conn.DeadSince.IsZero() {
+			t.Errorf("Unexpected value for DeadSince: %s", conn.DeadSince)
+		}
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 live connection, got: %d", len(pool.live))
+		}
+
+		if len(pool.dead) != 3 {
+			t.Errorf("Expected 3 dead connections, got: %d", len(pool.dead))
+		}
+
+		expected := []string{
+			"http://foo4",
+			"http://foo1",
+			"http://foo3",
+		}
+
+		for i, u := range expected {
+			if pool.dead[i].URL.String() != u {
+				t.Errorf("Unexpected value for item %d in pool.dead: %s", i, pool.dead[i].URL.String())
+			}
+		}
+	})
+
+	t.Run("Short circuit when the connection is already dead", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			live: []*Connection{
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo2"}},
+				&Connection{URL: &url.URL{Scheme: "http", Host: "foo3"}},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := pool.live[0]
+		conn.IsDead = true
+
+		if err := pool.OnFailure(conn); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if len(pool.dead) != 0 {
+			t.Errorf("Expected the dead list to be empty, got: %s", pool.dead)
+		}
+	})
+}
+
+func TestStatusConnectionPoolResurrect(t *testing.T) {
+	t.Run("Mark the connection as dead and add/remove it to the lists", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			live:     []*Connection{},
+			dead:     []*Connection{&Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}, IsDead: true}},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := pool.dead[0]
+
+		if err := pool.resurrect(conn, true); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if conn.IsDead {
+			t.Errorf("Expected connection to be dead, got: %s", conn)
+		}
+
+		if len(pool.dead) != 0 {
+			t.Errorf("Expected no dead connections, got: %s", pool.dead)
+		}
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 live connection, got: %s", pool.live)
+		}
+	})
+
+	t.Run("Short circuit removal when the connection is not in the dead list", func(t *testing.T) {
+		pool := &statusConnectionPool{
+			dead:     []*Connection{&Connection{URL: &url.URL{Scheme: "http", Host: "bar"}, IsDead: true}},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := &Connection{URL: &url.URL{Scheme: "http", Host: "foo1"}, IsDead: true}
+
+		if err := pool.resurrect(conn, true); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 live connection, got: %s", pool.live)
+		}
+
+		if len(pool.dead) != 1 {
+			t.Errorf("Expected 1 dead connection, got: %s", pool.dead)
+		}
+	})
+
+	t.Run("Schedule resurrect", func(t *testing.T) {
+		defaultResurrectTimeoutInitial = 0
+		defer func() { defaultResurrectTimeoutInitial = 60 * time.Second }()
+
+		pool := &statusConnectionPool{
+			live: []*Connection{},
+			dead: []*Connection{
+				&Connection{
+					URL:       &url.URL{Scheme: "http", Host: "foo1"},
+					Failures:  100,
+					IsDead:    true,
+					DeadSince: time.Now().UTC(),
+				},
+			},
+			selector: &roundRobinSelector{curr: -1},
+		}
+
+		conn := pool.dead[0]
+		pool.scheduleResurrect(conn)
+		time.Sleep(50 * time.Millisecond)
+
+		pool.Lock()
+		defer pool.Unlock()
+
+		if len(pool.live) != 1 {
+			t.Errorf("Expected 1 live connection, got: %s", pool.live)
+		}
+		if len(pool.dead) != 0 {
+			t.Errorf("Expected no dead connections, got: %s", pool.dead)
+		}
+	})
+}
+
+func TestConnection(t *testing.T) {
+	t.Run("String", func(t *testing.T) {
+		conn := &Connection{
+			URL:       &url.URL{Scheme: "http", Host: "foo1"},
+			Failures:  10,
+			IsDead:    true,
+			DeadSince: time.Now().UTC(),
+		}
+
+		match, err := regexp.MatchString(
+			`<http://foo1> dead=true failures=10`,
+			conn.String(),
+		)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if !match {
+			t.Errorf("Unexpected output: %s", conn)
+		}
+	})
+}
diff --git a/estransport/discovery.go b/estransport/discovery.go
new file mode 100644
index 0000000000..ccbb586a34
--- /dev/null
+++ b/estransport/discovery.go
@@ -0,0 +1,218 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+)
+
+// Discoverable defines the interface for transports supporting node discovery.
+//
+type Discoverable interface {
+	DiscoverNodes() error
+}
+
+// nodeInfo represents the information about node in a cluster.
+//
+// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-info.html
+//
+type nodeInfo struct {
+	ID         string
+	Name       string
+	URL        *url.URL
+	Roles      []string `json:"roles"`
+	Attributes map[string]interface{}
+	HTTP       struct {
+		PublishAddress string `json:"publish_address"`
+	}
+}
+
+// DiscoverNodes reloads the client connections by fetching information from the cluster.
+//
+func (c *Client) DiscoverNodes() error {
+	var conns []*Connection
+
+	nodes, err := c.getNodesInfo()
+	if err != nil {
+		if debugLogger != nil {
+			debugLogger.Logf("Error getting nodes info: %s\n", err)
+		}
+		return fmt.Errorf("discovery: get nodes: %s", err)
+	}
+
+	for _, node := range nodes {
+		var (
+			isMasterOnlyNode bool
+		)
+
+		roles := append(node.Roles[:0:0], node.Roles...)
+		sort.Strings(roles)
+
+		if len(roles) == 1 && roles[0] == "master" {
+			isMasterOnlyNode = true
+		}
+
+		if debugLogger != nil {
+			var skip string
+			if isMasterOnlyNode {
+				skip = "; [SKIP]"
+			}
+			debugLogger.Logf("Discovered node [%s]; %s; roles=%s%s\n", node.Name, node.URL, node.Roles, skip)
+		}
+
+		// Skip master only nodes
+		// TODO(karmi): Move logic to Selector?
+		if isMasterOnlyNode {
+			continue
+		}
+
+		conns = append(conns, &Connection{
+			URL:        node.URL,
+			ID:         node.ID,
+			Name:       node.Name,
+			Roles:      node.Roles,
+			Attributes: node.Attributes,
+		})
+	}
+
+	c.Lock()
+	defer c.Unlock()
+
+	if lockable, ok := c.pool.(sync.Locker); ok {
+		lockable.Lock()
+		defer lockable.Unlock()
+	}
+
+	if c.poolFunc != nil {
+		c.pool = c.poolFunc(conns, c.selector)
+	} else {
+		// TODO(karmi): Replace only live connections, leave dead scheduled for resurrect?
+		c.pool, err = NewConnectionPool(conns, c.selector)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (c *Client) getNodesInfo() ([]nodeInfo, error) {
+	var (
+		out    []nodeInfo
+		scheme = c.urls[0].Scheme
+	)
+
+	req, err := http.NewRequest("GET", "/_nodes/http", nil)
+	if err != nil {
+		return out, err
+	}
+
+	c.Lock()
+	conn, err := c.pool.Next()
+	c.Unlock()
+	// TODO(karmi): If no connection is returned, fallback to original URLs
+	if err != nil {
+		return out, err
+	}
+
+	c.setReqURL(conn.URL, req)
+	c.setReqAuth(conn.URL, req)
+	c.setReqUserAgent(req)
+
+	if c.disableMetaHeader == false {
+		c.setMetaHeader(req)
+	}
+
+	res, err := c.transport.RoundTrip(req)
+	if err != nil {
+		return out, err
+	}
+	defer res.Body.Close()
+
+	if res.StatusCode > 200 {
+		body, _ := ioutil.ReadAll(res.Body)
+		return out, fmt.Errorf("server error: %s: %s", res.Status, body)
+	}
+
+	var env map[string]json.RawMessage
+	if err := json.NewDecoder(res.Body).Decode(&env); err != nil {
+		return out, err
+	}
+
+	var nodes map[string]nodeInfo
+	if err := json.Unmarshal(env["nodes"], &nodes); err != nil {
+		return out, err
+	}
+
+	for id, node := range nodes {
+		node.ID = id
+		u, err := c.getNodeURL(node, scheme)
+		if err != nil {
+			return out, err
+		}
+		node.URL = u
+		out = append(out, node)
+	}
+
+	return out, nil
+}
+
+func (c *Client) getNodeURL(node nodeInfo, scheme string) (*url.URL, error) {
+	var (
+		host string
+		port string
+
+		addrs = strings.Split(node.HTTP.PublishAddress, "/")
+		ports = strings.Split(node.HTTP.PublishAddress, ":")
+	)
+
+	if len(addrs) > 1 {
+		host = addrs[0]
+	} else {
+		host = strings.Split(addrs[0], ":")[0]
+	}
+	port = ports[len(ports)-1]
+
+	u := &url.URL{
+		Scheme: scheme,
+		Host:   host + ":" + port,
+	}
+
+	return u, nil
+}
+
+func (c *Client) scheduleDiscoverNodes(d time.Duration) {
+	go c.DiscoverNodes()
+
+	c.Lock()
+	defer c.Unlock()
+	if c.discoverNodesTimer != nil {
+		c.discoverNodesTimer.Stop()
+	}
+	c.discoverNodesTimer = time.AfterFunc(c.discoverNodesInterval, func() {
+		c.scheduleDiscoverNodes(c.discoverNodesInterval)
+	})
+}
diff --git a/estransport/discovery_internal_test.go b/estransport/discovery_internal_test.go
new file mode 100644
index 0000000000..2250cfb63f
--- /dev/null
+++ b/estransport/discovery_internal_test.go
@@ -0,0 +1,404 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package estransport
+
+import (
+	"bytes"
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestDiscovery(t *testing.T) {
+	defaultHandler := func(w http.ResponseWriter, r *http.Request) {
+		f, err := os.Open("testdata/nodes.info.json")
+		if err != nil {
+			http.Error(w, fmt.Sprintf("Fixture error: %s", err), 500)
+			return
+		}
+		io.Copy(w, f)
+	}
+
+	srv := &http.Server{Addr: "localhost:10001", Handler: http.HandlerFunc(defaultHandler)}
+	srvTLS := &http.Server{Addr: "localhost:12001", Handler: http.HandlerFunc(defaultHandler)}
+
+	go func() {
+		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+			t.Errorf("Unable to start server: %s", err)
+			return
+		}
+	}()
+	go func() {
+		if err := srvTLS.ListenAndServeTLS("testdata/cert.pem", "testdata/key.pem"); err != nil && err != http.ErrServerClosed {
+			t.Errorf("Unable to start server: %s", err)
+			return
+		}
+	}()
+	defer func() { srv.Close() }()
+	defer func() { srvTLS.Close() }()
+
+	time.Sleep(50 * time.Millisecond)
+
+	t.Run("getNodesInfo()", func(t *testing.T) {
+		u, _ := url.Parse("http://" + srv.Addr)
+		tp, _ := New(Config{URLs: []*url.URL{u}})
+
+		nodes, err := tp.getNodesInfo()
+		if err != nil {
+			t.Fatalf("ERROR: %s", err)
+		}
+		fmt.Printf("NodesInfo: %+v\n", nodes)
+
+		if len(nodes) != 3 {
+			t.Errorf("Unexpected number of nodes, want=3, got=%d", len(nodes))
+		}
+
+		for _, node := range nodes {
+			switch node.Name {
+			case "es1":
+				if node.URL.String() != "http://127.0.0.1:10001" {
+					t.Errorf("Unexpected URL: %s", node.URL.String())
+				}
+			case "es2":
+				if node.URL.String() != "http://localhost:10002" {
+					t.Errorf("Unexpected URL: %s", node.URL.String())
+				}
+			case "es3":
+				if node.URL.String() != "http://127.0.0.1:10003" {
+					t.Errorf("Unexpected URL: %s", node.URL.String())
+				}
+			}
+		}
+	})
+
+	t.Run("DiscoverNodes()", func(t *testing.T) {
+		u, _ := url.Parse("http://" + srv.Addr)
+		tp, _ := New(Config{URLs: []*url.URL{u}})
+
+		tp.DiscoverNodes()
+
+		pool, ok := tp.pool.(*statusConnectionPool)
+		if !ok {
+			t.Fatalf("Unexpected pool, want=statusConnectionPool, got=%T", tp.pool)
+		}
+
+		if len(pool.live) != 2 {
+			t.Errorf("Unexpected number of nodes, want=2, got=%d", len(pool.live))
+		}
+
+		for _, conn := range pool.live {
+			switch conn.Name {
+			case "es1":
+				if conn.URL.String() != "http://127.0.0.1:10001" {
+					t.Errorf("Unexpected URL: %s", conn.URL.String())
+				}
+			case "es2":
+				if conn.URL.String() != "http://localhost:10002" {
+					t.Errorf("Unexpected URL: %s", conn.URL.String())
+				}
+			default:
+				t.Errorf("Unexpected node: %s", conn.Name)
+			}
+		}
+	})
+
+	t.Run("DiscoverNodes() with SSL and authorization", func(t *testing.T) {
+		u, _ := url.Parse("https://" + srvTLS.Addr)
+		tp, _ := New(Config{
+			URLs:     []*url.URL{u},
+			Username: "foo",
+			Password: "bar",
+			Transport: &http.Transport{
+				TLSClientConfig: &tls.Config{
+					InsecureSkipVerify: true,
+				},
+			},
+		})
+
+		tp.DiscoverNodes()
+
+		pool, ok := tp.pool.(*statusConnectionPool)
+		if !ok {
+			t.Fatalf("Unexpected pool, want=statusConnectionPool, got=%T", tp.pool)
+		}
+
+		if len(pool.live) != 2 {
+			t.Errorf("Unexpected number of nodes, want=2, got=%d", len(pool.live))
+		}
+
+		for _, conn := range pool.live {
+			switch conn.Name {
+			case "es1":
+				if conn.URL.String() != "https://127.0.0.1:10001" {
+					t.Errorf("Unexpected URL: %s", conn.URL.String())
+				}
+			case "es2":
+				if conn.URL.String() != "https://localhost:10002" {
+					t.Errorf("Unexpected URL: %s", conn.URL.String())
+				}
+			default:
+				t.Errorf("Unexpected node: %s", conn.Name)
+			}
+		}
+	})
+
+	t.Run("scheduleDiscoverNodes()", func(t *testing.T) {
+		t.Skip("Skip") // TODO(karmi): Investigate the intermittent failures of this test
+
+		var numURLs int
+		u, _ := url.Parse("http://" + srv.Addr)
+
+		tp, _ := New(Config{URLs: []*url.URL{u}, DiscoverNodesInterval: 10 * time.Millisecond})
+
+		tp.Lock()
+		numURLs = len(tp.pool.URLs())
+		tp.Unlock()
+		if numURLs != 1 {
+			t.Errorf("Unexpected number of nodes, want=1, got=%d", numURLs)
+		}
+
+		time.Sleep(18 * time.Millisecond) // Wait until (*Client).scheduleDiscoverNodes()
+		tp.Lock()
+		numURLs = len(tp.pool.URLs())
+		tp.Unlock()
+		if numURLs != 2 {
+			t.Errorf("Unexpected number of nodes, want=2, got=%d", numURLs)
+		}
+	})
+
+	t.Run("Role based nodes discovery", func(t *testing.T) {
+		type Node struct {
+			URL string
+			Roles []string
+		}
+
+		type fields struct {
+			Nodes map[string]Node
+		}
+		type wants struct {
+			wantErr bool
+			wantsNConn int
+		}
+		tests := []struct {
+			name    string
+			args  fields
+			want  wants
+		}{
+			{
+				"Default roles should allow every node to be selected",
+				fields{
+					Nodes: map[string]Node{
+						"es1": {
+							URL: "http://es1:9200",
+							Roles: []string{
+								"data",
+								"data_cold",
+								"data_content",
+								"data_frozen",
+								"data_hot",
+								"data_warm",
+								"ingest",
+								"master",
+								"ml",
+								"remote_cluster_client",
+								"transform",
+							},
+						},
+						"es2": {
+							URL: "http://es2:9200",
+							Roles: []string{
+								"data",
+								"data_cold",
+								"data_content",
+								"data_frozen",
+								"data_hot",
+								"data_warm",
+								"ingest",
+								"master",
+								"ml",
+								"remote_cluster_client",
+								"transform",
+							},
+						},
+						"es3": {
+							URL: "http://es3:9200",
+							Roles: []string{
+								"data",
+								"data_cold",
+								"data_content",
+								"data_frozen",
+								"data_hot",
+								"data_warm",
+								"ingest",
+								"master",
+								"ml",
+								"remote_cluster_client",
+								"transform",
+							},
+						},
+					},
+				},
+				wants{
+					false, 3,
+				},
+			},
+			{
+				"Master only node should not be selected",
+				fields{
+					Nodes: map[string]Node{
+						"es1": {
+							URL: "http://es1:9200",
+							Roles: []string{
+								"master",
+							},
+						},
+						"es2": {
+							URL: "http://es2:9200",
+							Roles: []string{
+								"data",
+								"data_cold",
+								"data_content",
+								"data_frozen",
+								"data_hot",
+								"data_warm",
+								"ingest",
+								"master",
+								"ml",
+								"remote_cluster_client",
+								"transform",
+							},
+						},
+						"es3": {
+							URL: "http://es3:9200",
+							Roles: []string{
+								"data",
+								"data_cold",
+								"data_content",
+								"data_frozen",
+								"data_hot",
+								"data_warm",
+								"ingest",
+								"master",
+								"ml",
+								"remote_cluster_client",
+								"transform",
+							},
+						},
+					},
+				},
+
+				wants{
+					false, 2,
+				},
+			},
+			{
+				"Master and data only nodes should be selected",
+				fields{
+					Nodes: map[string]Node{
+						"es1": {
+							URL: "http://es1:9200",
+							Roles: []string{
+								"data",
+								"master",
+							},
+						},
+						"es2": {
+							URL: "http://es2:9200",
+							Roles: []string{
+								"data",
+								"master",
+							},
+						},
+					},
+				},
+
+				wants{
+					false, 2,
+				},
+			},
+		}
+		for _, tt := range tests {
+			t.Run(tt.name, func(t *testing.T) {
+				var names []string
+				var urls []*url.URL
+				for name, node := range tt.args.Nodes {
+					u, _ := url.Parse(node.URL)
+					urls = append(urls, u)
+					names = append(names, name)
+				}
+
+				newRoundTripper := func() http.RoundTripper {
+					return &mockTransp{
+						RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+							nodes := make(map[string]map[string]nodeInfo)
+							nodes["nodes"] = make(map[string]nodeInfo)
+							for name, node := range tt.args.Nodes {
+								nodes["nodes"][name] = nodeInfo{Roles: node.Roles}
+							}
+
+							b, _ := json.Marshal(nodes)
+
+							return &http.Response{
+								Status:        "200 OK",
+								StatusCode:    200,
+								ContentLength: int64(len(b)),
+								Header:        http.Header(map[string][]string{"Content-Type": {"application/json"}}),
+								Body:          ioutil.NopCloser(bytes.NewReader(b)),
+							}, nil
+						},
+					}
+				}
+
+				c, _ := New(Config{
+					URLs:     urls,
+					Transport: newRoundTripper(),
+				})
+				c.DiscoverNodes()
+
+				pool, ok := c.pool.(*statusConnectionPool)
+				if !ok {
+					t.Fatalf("Unexpected pool, want=statusConnectionPool, got=%T", c.pool)
+				}
+
+				if len(pool.live) != tt.want.wantsNConn {
+					t.Errorf("Unexpected number of nodes, want=%d, got=%d", tt.want.wantsNConn, len(pool.live))
+				}
+
+				for _, conn := range pool.live {
+					if !reflect.DeepEqual(tt.args.Nodes[conn.ID].Roles, conn.Roles) {
+						t.Errorf("Unexpected roles for node %s, want=%s, got=%s", conn.Name, tt.args.Nodes[conn.ID], conn.Roles)
+					}
+				}
+
+				if err := c.DiscoverNodes(); (err != nil) != tt.want.wantErr {
+					t.Errorf("DiscoverNodes() error = %v, wantErr %v", err, tt.want.wantErr)
+				}
+			})
+		}
+	})
+}
diff --git a/estransport/doc.go b/estransport/doc.go
old mode 100755
new mode 100644
index aa3eba3f95..5673107433
--- a/estransport/doc.go
+++ b/estransport/doc.go
@@ -1,17 +1,51 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 /*
 Package estransport provides the transport layer for the Elasticsearch client.
 
 It is automatically included in the client provided by the github.com/elastic/go-elasticsearch package
 and is not intended for direct use: to configure the client, use the elasticsearch.Config struct.
 
-The default HTTP transport of the client is http.Transport.
+The default HTTP transport of the client is http.Transport; use the Transport option to customize it;
+see the _examples/coniguration.go and _examples/customization.go files in this repository for information.
+
+The package will automatically retry requests on network-related errors, and on specific
+response status codes (by default 502, 503, 504). Use the RetryOnStatus option to customize the list.
+The transport will not retry a timeout network error, unless enabled by setting EnableRetryOnTimeout to true.
+
+Use the MaxRetries option to configure the number of retries, and set DisableRetry to true
+to disable the retry behaviour altogether.
 
-The package defines the "Selector" interface for getting a URL from the list. At the moment,
-the implementation is rather minimal: the client takes a slice of url.URL pointers,
-and round-robins across them when performing the request.
+By default, the retry will be performed without any delay; to configure a backoff interval,
+implement the RetryBackoff option function; see an example in the package unit tests for information.
 
-The package defines the "Logger" interface for logging information about request and response.
+When multiple addresses are passed in configuration, the package will use them in a round-robin fashion,
+and will keep track of live and dead nodes. The status of dead nodes is checked periodically.
+
+To customize the node selection behaviour, provide a Selector implementation in the configuration.
+To replace the connection pool entirely, provide a custom ConnectionPool implementation via
+the ConnectionPoolFunc option.
+
+The package defines the Logger interface for logging information about request and response.
 It comes with several bundled loggers for logging in text and JSON.
 
+Use the EnableDebugLogger option to enable the debugging logger for connection management.
+
+Use the EnableMetrics option to enable metric collection and export.
 */
 package estransport
diff --git a/estransport/estransport.go b/estransport/estransport.go
old mode 100755
new mode 100644
index 87266383df..6680e26cc1
--- a/estransport/estransport.go
+++ b/estransport/estransport.go
@@ -1,25 +1,73 @@
-package estransport // import "github.com/elastic/go-elasticsearch/estransport"
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
 
 import (
 	"bytes"
+	"compress/gzip"
+	"crypto/sha256"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/hex"
+	"errors"
 	"fmt"
+	"io"
 	"io/ioutil"
+	"net"
 	"net/http"
 	"net/url"
+	"os"
+	"regexp"
+	"runtime"
+	"strconv"
 	"strings"
+	"sync"
 	"time"
 
-	"github.com/elastic/go-elasticsearch/internal/version"
+	"github.com/elastic/go-elasticsearch/v7/internal/version"
 )
 
-// Version returns the package version as a string.
-//
-const Version = version.Client
+const (
+	// Version returns the package version as a string.
+	Version = version.Client
+
+	// esCompatHeader defines the env var for Compatibility header.
+	esCompatHeader = "ELASTIC_CLIENT_APIVERSIONING"
 
-var userAgent string
+	userAgentHeader = "User-Agent"
+)
+
+var (
+	userAgent           string
+	metaHeader          string
+	compatibilityHeader bool
+	reGoVersion         = regexp.MustCompile(`go(\d+\.\d+\..+)`)
+
+	defaultMaxRetries    = 3
+	defaultRetryOnStatus = [...]int{502, 503, 504}
+)
 
 func init() {
-	userAgent = strings.Join([]string{"go-elasticsearch", Version}, "/")
+	userAgent = initUserAgent()
+	metaHeader = initMetaHeader()
+
+	compatHeaderEnv := os.Getenv(esCompatHeader)
+	compatibilityHeader, _ = strconv.ParseBool(compatHeaderEnv)
 }
 
 // Interface defines the interface for HTTP client.
@@ -31,90 +79,374 @@ type Interface interface {
 // Config represents the configuration of HTTP client.
 //
 type Config struct {
-	URLs     []*url.URL
-	Username string
-	Password string
+	URLs         []*url.URL
+	Username     string
+	Password     string
+	APIKey       string
+	ServiceToken string
+
+	Header http.Header
+	CACert []byte
+
+	RetryOnStatus        []int
+	DisableRetry         bool
+	EnableRetryOnTimeout bool
+	MaxRetries           int
+	RetryBackoff         func(attempt int) time.Duration
+
+	CompressRequestBody bool
+	CompatibilityHeader bool
+
+	EnableMetrics     bool
+	EnableDebugLogger bool
+
+	DisableMetaHeader bool
+
+	DiscoverNodesInterval time.Duration
 
 	Transport http.RoundTripper
 	Logger    Logger
+	Selector  Selector
+
+	ConnectionPoolFunc func([]*Connection, Selector) ConnectionPool
+
+	CertificateFingerprint string
 }
 
 // Client represents the HTTP client.
 //
 type Client struct {
-	urls     []*url.URL
-	username string
-	password string
+	sync.Mutex
+
+	urls         []*url.URL
+	username     string
+	password     string
+	apikey       string
+	servicetoken string
+	fingerprint  string
+	header       http.Header
+
+	retryOnStatus         []int
+	disableRetry          bool
+	enableRetryOnTimeout  bool
+	disableMetaHeader     bool
+	maxRetries            int
+	retryBackoff          func(attempt int) time.Duration
+	discoverNodesInterval time.Duration
+	discoverNodesTimer    *time.Timer
+
+	compressRequestBody bool
+	compatibilityHeader bool
+
+	metrics *metrics
 
 	transport http.RoundTripper
-	selector  Selector
 	logger    Logger
+	selector  Selector
+	pool      ConnectionPool
+	poolFunc  func([]*Connection, Selector) ConnectionPool
 }
 
-// New creates new HTTP client.
+// New creates new transport client.
 //
 // http.DefaultTransport will be used if no transport is passed in the configuration.
 //
-func New(cfg Config) *Client {
+func New(cfg Config) (*Client, error) {
 	if cfg.Transport == nil {
 		cfg.Transport = http.DefaultTransport
 	}
 
-	return &Client{
-		urls:     cfg.URLs,
-		username: cfg.Username,
-		password: cfg.Password,
+	if transport, ok := cfg.Transport.(*http.Transport); ok {
+		if cfg.CertificateFingerprint != "" {
+			transport.DialTLS = func(network, addr string) (net.Conn, error) {
+				fingerprint, _ := hex.DecodeString(cfg.CertificateFingerprint)
+
+				c, err := tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: true})
+				if err != nil {
+					return nil, err
+				}
+
+				// Retrieve the connection state from the remote server.
+				cState := c.ConnectionState()
+				for _, cert := range cState.PeerCertificates {
+					// Compute digest for each certificate.
+					digest := sha256.Sum256(cert.Raw)
+
+					// Provided fingerprint should match at least one certificate from remote before we continue.
+					if bytes.Compare(digest[0:], fingerprint) == 0 {
+						return c, nil
+					}
+				}
+				return nil, fmt.Errorf("fingerprint mismatch, provided: %s", cfg.CertificateFingerprint)
+			}
+		}
+	}
+
+	if cfg.CACert != nil {
+		httpTransport, ok := cfg.Transport.(*http.Transport)
+		if !ok {
+			return nil, fmt.Errorf("unable to set CA certificate for transport of type %T", cfg.Transport)
+		}
+
+		httpTransport = httpTransport.Clone()
+		httpTransport.TLSClientConfig.RootCAs = x509.NewCertPool()
+
+		if ok := httpTransport.TLSClientConfig.RootCAs.AppendCertsFromPEM(cfg.CACert); !ok {
+			return nil, errors.New("unable to add CA certificate")
+		}
+
+		cfg.Transport = httpTransport
+	}
+
+	if len(cfg.RetryOnStatus) == 0 {
+		cfg.RetryOnStatus = defaultRetryOnStatus[:]
+	}
+
+	if cfg.MaxRetries == 0 {
+		cfg.MaxRetries = defaultMaxRetries
+	}
+
+	var conns []*Connection
+	for _, u := range cfg.URLs {
+		conns = append(conns, &Connection{URL: u})
+	}
+
+	client := Client{
+		urls:         cfg.URLs,
+		username:     cfg.Username,
+		password:     cfg.Password,
+		apikey:       cfg.APIKey,
+		servicetoken: cfg.ServiceToken,
+		header:       cfg.Header,
+
+		retryOnStatus:         cfg.RetryOnStatus,
+		disableRetry:          cfg.DisableRetry,
+		enableRetryOnTimeout:  cfg.EnableRetryOnTimeout,
+		disableMetaHeader:     cfg.DisableMetaHeader,
+		maxRetries:            cfg.MaxRetries,
+		retryBackoff:          cfg.RetryBackoff,
+		discoverNodesInterval: cfg.DiscoverNodesInterval,
+
+		compressRequestBody: cfg.CompressRequestBody,
+		compatibilityHeader: cfg.CompatibilityHeader,
 
 		transport: cfg.Transport,
-		selector:  NewRoundRobinSelector(cfg.URLs...),
 		logger:    cfg.Logger,
+		selector:  cfg.Selector,
+		poolFunc:  cfg.ConnectionPoolFunc,
+	}
+
+	if client.poolFunc != nil {
+		client.pool = client.poolFunc(conns, client.selector)
+	} else {
+		client.pool, _ = NewConnectionPool(conns, client.selector)
+	}
+
+	if cfg.EnableDebugLogger {
+		debugLogger = &debuggingLogger{Output: os.Stdout}
 	}
+
+	if cfg.EnableMetrics {
+		client.metrics = &metrics{responses: make(map[int]int)}
+		// TODO(karmi): Type assertion to interface
+		if pool, ok := client.pool.(*singleConnectionPool); ok {
+			pool.metrics = client.metrics
+		}
+		if pool, ok := client.pool.(*statusConnectionPool); ok {
+			pool.metrics = client.metrics
+		}
+	}
+
+	if client.discoverNodesInterval > 0 {
+		time.AfterFunc(client.discoverNodesInterval, func() {
+			client.scheduleDiscoverNodes(client.discoverNodesInterval)
+		})
+	}
+
+	return &client, nil
 }
 
 // Perform executes the request and returns a response or error.
 //
 func (c *Client) Perform(req *http.Request) (*http.Response, error) {
-	u, err := c.getURL()
-	if err != nil {
-		// TODO(karmi): Log error
-		return nil, fmt.Errorf("cannot get URL: %s", err)
+	var (
+		res *http.Response
+		err error
+	)
+
+	// Compatibility Header
+	if compatibilityHeader || c.compatibilityHeader {
+		if req.Body != nil {
+			req.Header.Set("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7")
+		}
+		req.Header.Set("Accept", "application/vnd.elasticsearch+json;compatible-with=7")
+	}
+
+	// Record metrics, when enabled
+	if c.metrics != nil {
+		c.metrics.Lock()
+		c.metrics.requests++
+		c.metrics.Unlock()
 	}
 
-	c.setURL(u, req)
-	c.setBasicAuth(u, req)
-	c.setUserAgent(req)
+	// Update request
+	c.setReqUserAgent(req)
+	c.setReqGlobalHeader(req)
+	c.setMetaHeader(req)
+
+	if req.Body != nil && req.Body != http.NoBody {
+		if c.compressRequestBody {
+			var buf bytes.Buffer
+			zw := gzip.NewWriter(&buf)
+			if _, err := io.Copy(zw, req.Body); err != nil {
+				return nil, fmt.Errorf("failed to compress request body: %s", err)
+			}
+			if err := zw.Close(); err != nil {
+				return nil, fmt.Errorf("failed to compress request body (during close): %s", err)
+			}
+
+			req.GetBody = func() (io.ReadCloser, error) {
+				r := buf
+				return ioutil.NopCloser(&r), nil
+			}
+			req.Body, _ = req.GetBody()
 
-	var dupReqBody *bytes.Buffer
-	if c.logger != nil && c.logger.RequestBodyEnabled() {
-		if req.Body != nil && req.Body != http.NoBody {
-			dupReqBody = bytes.NewBuffer(make([]byte, 0, int(req.ContentLength)))
-			dupReqBody.ReadFrom(req.Body)
-			req.Body = ioutil.NopCloser(bytes.NewBuffer(dupReqBody.Bytes()))
+			req.Header.Set("Content-Encoding", "gzip")
+			req.ContentLength = int64(buf.Len())
+
+		} else if req.GetBody == nil {
+			if !c.disableRetry || (c.logger != nil && c.logger.RequestBodyEnabled()) {
+				var buf bytes.Buffer
+				buf.ReadFrom(req.Body)
+
+				req.GetBody = func() (io.ReadCloser, error) {
+					r := buf
+					return ioutil.NopCloser(&r), nil
+				}
+				req.Body, _ = req.GetBody()
+			}
 		}
 	}
 
-	start := time.Now().UTC()
-	res, err := c.transport.RoundTrip(req)
-	dur := time.Since(start)
+	for i := 0; i <= c.maxRetries; i++ {
+		var (
+			conn            *Connection
+			shouldRetry     bool
+			shouldCloseBody bool
+		)
 
-	if c.logger != nil {
-		var dupRes http.Response
-		if res != nil {
-			dupRes = *res
+		// Get connection from the pool
+		c.Lock()
+		conn, err = c.pool.Next()
+		c.Unlock()
+		if err != nil {
+			if c.logger != nil {
+				c.logRoundTrip(req, nil, err, time.Time{}, time.Duration(0))
+			}
+			return nil, fmt.Errorf("cannot get connection: %s", err)
 		}
-		if c.logger.RequestBodyEnabled() {
-			if req.Body != nil && req.Body != http.NoBody {
-				req.Body = ioutil.NopCloser(dupReqBody)
+
+		// Update request
+		c.setReqURL(conn.URL, req)
+		c.setReqAuth(conn.URL, req)
+
+		if !c.disableRetry && i > 0 && req.Body != nil && req.Body != http.NoBody {
+			body, err := req.GetBody()
+			if err != nil {
+				return nil, fmt.Errorf("cannot get request body: %s", err)
 			}
+			req.Body = body
 		}
-		if c.logger.ResponseBodyEnabled() {
-			if res.Body != nil && res.Body != http.NoBody {
-				b1, b2, _ := duplicateBody(res.Body)
-				dupRes.Body = b1
-				res.Body = b2
+
+		// Set up time measures and execute the request
+		start := time.Now().UTC()
+		res, err = c.transport.RoundTrip(req)
+		dur := time.Since(start)
+
+		// Log request and response
+		if c.logger != nil {
+			if c.logger.RequestBodyEnabled() && req.Body != nil && req.Body != http.NoBody {
+				req.Body, _ = req.GetBody()
+			}
+			c.logRoundTrip(req, res, err, start, dur)
+		}
+
+		if err != nil {
+			// Record metrics, when enabled
+			if c.metrics != nil {
+				c.metrics.Lock()
+				c.metrics.failures++
+				c.metrics.Unlock()
+			}
+
+			// Report the connection as unsuccessful
+			c.Lock()
+			c.pool.OnFailure(conn)
+			c.Unlock()
+
+			// Retry on EOF errors
+			if err == io.EOF {
+				shouldRetry = true
+			}
+
+			// Retry on network errors, but not on timeout errors, unless configured
+			if err, ok := err.(net.Error); ok {
+				if (!err.Timeout() || c.enableRetryOnTimeout) && !c.disableRetry {
+					shouldRetry = true
+				}
+			}
+		} else {
+			// Report the connection as succesfull
+			c.Lock()
+			c.pool.OnSuccess(conn)
+			c.Unlock()
+		}
+
+		if res != nil && c.metrics != nil {
+			c.metrics.Lock()
+			c.metrics.responses[res.StatusCode]++
+			c.metrics.Unlock()
+		}
+
+		// Retry on configured response statuses
+		if res != nil && !c.disableRetry {
+			for _, code := range c.retryOnStatus {
+				if res.StatusCode == code {
+					shouldRetry = true
+					shouldCloseBody = true
+				}
+			}
+		}
+
+		// Break if retry should not be performed
+		if !shouldRetry {
+			break
+		}
+
+		// Drain and close body when retrying after response
+		if shouldCloseBody && i < c.maxRetries {
+			if res.Body != nil {
+				io.Copy(ioutil.Discard, res.Body)
+				res.Body.Close()
+			}
+		}
+
+		// Delay the retry if a backoff function is configured
+		if c.retryBackoff != nil {
+			var cancelled bool
+			backoff := c.retryBackoff(i + 1)
+			timer := time.NewTimer(backoff)
+			select {
+			case <-req.Context().Done():
+				err = req.Context().Err()
+				cancelled = true
+				timer.Stop()
+			case <-timer.C:
+			}
+			if cancelled {
+				break
 			}
 		}
-		c.logger.LogRoundTrip(req, &dupRes, err, start, dur) // errcheck exclude
 	}
 
 	// TODO(karmi): Wrap error
@@ -123,15 +455,12 @@ func (c *Client) Perform(req *http.Request) (*http.Response, error) {
 
 // URLs returns a list of transport URLs.
 //
+//
 func (c *Client) URLs() []*url.URL {
-	return c.urls
-}
-
-func (c *Client) getURL() (*url.URL, error) {
-	return c.selector.Select()
+	return c.pool.URLs()
 }
 
-func (c *Client) setURL(u *url.URL, req *http.Request) *http.Request {
+func (c *Client) setReqURL(u *url.URL, req *http.Request) *http.Request {
 	req.URL.Scheme = u.Scheme
 	req.URL.Host = u.Host
 
@@ -146,22 +475,121 @@ func (c *Client) setURL(u *url.URL, req *http.Request) *http.Request {
 	return req
 }
 
-func (c *Client) setBasicAuth(u *url.URL, req *http.Request) *http.Request {
-	if u.User != nil {
-		password, _ := u.User.Password()
-		req.SetBasicAuth(u.User.Username(), password)
-		return req
+func (c *Client) setReqAuth(u *url.URL, req *http.Request) *http.Request {
+	if _, ok := req.Header["Authorization"]; !ok {
+		if u.User != nil {
+			password, _ := u.User.Password()
+			req.SetBasicAuth(u.User.Username(), password)
+			return req
+		}
+
+		if c.apikey != "" {
+			var b bytes.Buffer
+			b.Grow(len("APIKey ") + len(c.apikey))
+			b.WriteString("APIKey ")
+			b.WriteString(c.apikey)
+			req.Header.Set("Authorization", b.String())
+			return req
+		}
+
+		if c.servicetoken != "" {
+			var b bytes.Buffer
+			b.Grow(len("Bearer ") + len(c.servicetoken))
+			b.WriteString("Bearer ")
+			b.WriteString(c.servicetoken)
+			req.Header.Set("Authorization", b.String())
+			return req
+		}
+
+		if c.username != "" && c.password != "" {
+			req.SetBasicAuth(c.username, c.password)
+			return req
+		}
 	}
 
-	if c.username != "" && c.password != "" {
-		req.SetBasicAuth(c.username, c.password)
-		return req
+	return req
+}
+
+func (c *Client) setReqUserAgent(req *http.Request) *http.Request {
+	if len(c.header) > 0 {
+		ua := c.header.Get(userAgentHeader)
+		if ua != "" {
+			req.Header.Set(userAgentHeader, ua)
+			return req
+		}
 	}
+	req.Header.Set(userAgentHeader, userAgent)
+	return req
+}
 
+func (c *Client) setReqGlobalHeader(req *http.Request) *http.Request {
+	if len(c.header) > 0 {
+		for k, v := range c.header {
+			if req.Header.Get(k) != k {
+				for _, vv := range v {
+					req.Header.Add(k, vv)
+				}
+			}
+		}
+	}
 	return req
 }
 
-func (c *Client) setUserAgent(req *http.Request) *http.Request {
-	req.Header.Set("User-Agent", userAgent)
+func (c *Client) setMetaHeader(req *http.Request) *http.Request {
+	if c.disableMetaHeader {
+		req.Header.Del(HeaderClientMeta)
+		return req
+	}
+
+	existingMetaHeader := req.Header.Get(HeaderClientMeta)
+	if existingMetaHeader != "" {
+		req.Header.Set(HeaderClientMeta, strings.Join([]string{metaHeader, existingMetaHeader}, ","))
+	} else {
+		req.Header.Add(HeaderClientMeta, metaHeader)
+	}
 	return req
 }
+
+func (c *Client) logRoundTrip(
+	req *http.Request,
+	res *http.Response,
+	err error,
+	start time.Time,
+	dur time.Duration,
+) {
+	var dupRes http.Response
+	if res != nil {
+		dupRes = *res
+	}
+	if c.logger.ResponseBodyEnabled() {
+		if res != nil && res.Body != nil && res.Body != http.NoBody {
+			b1, b2, _ := duplicateBody(res.Body)
+			dupRes.Body = b1
+			res.Body = b2
+		}
+	}
+	c.logger.LogRoundTrip(req, &dupRes, err, start, dur) // errcheck exclude
+}
+
+func initUserAgent() string {
+	var b strings.Builder
+
+	b.WriteString("go-elasticsearch")
+	b.WriteRune('/')
+	b.WriteString(Version)
+	b.WriteRune(' ')
+	b.WriteRune('(')
+	b.WriteString(runtime.GOOS)
+	b.WriteRune(' ')
+	b.WriteString(runtime.GOARCH)
+	b.WriteString("; ")
+	b.WriteString("Go ")
+	if v := reGoVersion.ReplaceAllString(runtime.Version(), "$1"); v != "" {
+		b.WriteString(v)
+	} else {
+		b.WriteString(runtime.Version())
+	}
+	b.WriteRune(')')
+
+	return b.String()
+}
diff --git a/estransport/estransport_benchmark_test.go b/estransport/estransport_benchmark_test.go
index e909eacfac..0aeb16afbb 100644
--- a/estransport/estransport_benchmark_test.go
+++ b/estransport/estransport_benchmark_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package estransport_test
@@ -9,7 +26,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
 var defaultResponse = http.Response{
@@ -37,8 +54,27 @@ func BenchmarkTransport(b *testing.B) {
 
 	b.Run("Defaults", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			tp := estransport.New(estransport.Config{
-				URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
+				Transport: newFakeTransport(b),
+			})
+
+			req, _ := http.NewRequest("GET", "/abc", nil)
+			_, err := tp.Perform(req)
+			if err != nil {
+				b.Fatalf("Unexpected error: %s", err)
+			}
+		}
+	})
+
+	b.Run("Headers", func(b *testing.B) {
+		hdr := http.Header{}
+		hdr.Set("Accept", "application/yaml")
+
+		for i := 0; i < b.N; i++ {
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
+				Header:    hdr,
 				Transport: newFakeTransport(b),
 			})
 
diff --git a/estransport/estransport_integration_multinode_test.go b/estransport/estransport_integration_multinode_test.go
new file mode 100644
index 0000000000..c8129736c6
--- /dev/null
+++ b/estransport/estransport_integration_multinode_test.go
@@ -0,0 +1,85 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build integration,multinode
+
+package estransport_test
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+var (
+	_ = fmt.Print
+)
+
+func TestTransportSelector(t *testing.T) {
+	NodeName := func(t *testing.T, transport estransport.Interface) string {
+		req, err := http.NewRequest("GET", "/", nil)
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		res, err := transport.Perform(req)
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		fmt.Printf("> GET %s\n", req.URL)
+
+		r := struct {
+			Name string
+		}{}
+
+		if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
+			t.Fatalf("Error parsing the response body: %s", err)
+		}
+
+		return r.Name
+	}
+
+	t.Run("RoundRobin", func(t *testing.T) {
+		var (
+			node string
+		)
+		transport, _ := estransport.New(estransport.Config{URLs: []*url.URL{
+			{Scheme: "http", Host: "localhost:9200"},
+			{Scheme: "http", Host: "localhost:9201"},
+		}})
+
+		node = NodeName(t, transport)
+		if node != "es1" {
+			t.Errorf("Unexpected node, want=e1, got=%s", node)
+		}
+
+		node = NodeName(t, transport)
+		if node != "es2" {
+			t.Errorf("Unexpected node, want=e1, got=%s", node)
+		}
+
+		node = NodeName(t, transport)
+		if node != "es1" {
+			t.Errorf("Unexpected node, want=e1, got=%s", node)
+		}
+	})
+}
diff --git a/estransport/estransport_integration_test.go b/estransport/estransport_integration_test.go
old mode 100755
new mode 100644
index b152953ef8..8548c1d137
--- a/estransport/estransport_integration_test.go
+++ b/estransport/estransport_integration_test.go
@@ -1,70 +1,161 @@
-// +build integration,multinode
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build integration
 
 package estransport_test
 
 import (
-	"encoding/json"
+	"bytes"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"net/http"
+	"net/http/httptest"
 	"net/url"
+	"strings"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
 )
 
 var (
 	_ = fmt.Print
 )
 
-func TestTransportSelector(t *testing.T) {
+func TestTransportRetries(t *testing.T) {
+	var counter int
 
-	NodeName := func(t *testing.T, transport estransport.Interface) string {
-		req, err := http.NewRequest("GET", "/", nil)
-		if err != nil {
-			t.Fatalf("Unexpected error: %s", err)
-		}
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		counter++
 
-		res, err := transport.Perform(req)
-		if err != nil {
-			t.Fatalf("Unexpected error: %s", err)
-		}
+		body, _ := ioutil.ReadAll(r.Body)
+		fmt.Println("req.Body:", string(body))
 
-		fmt.Printf("> GET %s\n", req.URL)
+		http.Error(w, "FAKE 502", http.StatusBadGateway)
+	}))
+	serverURL, _ := url.Parse(server.URL)
 
-		r := struct {
-			Name string
-		}{}
+	transport, _ := estransport.New(estransport.Config{URLs: []*url.URL{serverURL}})
 
-		if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
-			t.Fatalf("Error parsing the response body: %s", err)
-		}
+	bodies := []io.Reader{
+		strings.NewReader(`FAKE`),
+		esutil.NewJSONReader(`FAKE`),
+	}
+
+	for _, body := range bodies {
+		t.Run(fmt.Sprintf("Reset the %T request body", body), func(t *testing.T) {
+			counter = 0
+
+			req, err := http.NewRequest("GET", "/", body)
+			if err != nil {
+				t.Fatalf("Unexpected error: %s", err)
+			}
+
+			res, err := transport.Perform(req)
+			if err != nil {
+				t.Fatalf("Unexpected error: %s", err)
+			}
 
-		return r.Name
+			body, _ := ioutil.ReadAll(res.Body)
+
+			fmt.Println("> GET", req.URL)
+			fmt.Printf("< %s (tries: %d)\n", bytes.TrimSpace(body), counter)
+
+			if counter != 4 {
+				t.Errorf("Unexpected number of attempts, want=4, got=%d", counter)
+			}
+		})
 	}
+}
+
+func TestTransportHeaders(t *testing.T) {
+	u, _ := url.Parse("http://localhost:9200")
 
-	t.Run("RoundRobin", func(t *testing.T) {
-		var (
-			node string
-		)
-		transport := estransport.New(estransport.Config{URLs: []*url.URL{
-			{Scheme: "http", Host: "localhost:9200"},
-			{Scheme: "http", Host: "localhost:9201"},
-		}})
-
-		node = NodeName(t, transport)
-		if node != "es1" {
-			t.Errorf("Unexpected node, want=e1, got=%s", node)
-		}
-
-		node = NodeName(t, transport)
-		if node != "es2" {
-			t.Errorf("Unexpected node, want=e1, got=%s", node)
-		}
-
-		node = NodeName(t, transport)
-		if node != "es1" {
-			t.Errorf("Unexpected node, want=e1, got=%s", node)
-		}
+	hdr := http.Header{}
+	hdr.Set("Accept", "application/yaml")
 
+	tp, _ := estransport.New(estransport.Config{
+		URLs:   []*url.URL{u},
+		Header: hdr,
 	})
+
+	req, _ := http.NewRequest("GET", "/", nil)
+	res, err := tp.Perform(req)
+	if err != nil {
+		t.Fatalf("Unexpected error: %s", err)
+	}
+	defer res.Body.Close()
+
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatalf("Unexpected error: %s", err)
+	}
+
+	if !bytes.HasPrefix(body, []byte("---")) {
+		t.Errorf("Unexpected response body:\n%s", body)
+	}
 }
+
+func TestTransportCompression(t *testing.T) {
+	var req *http.Request
+	var res *http.Response
+	var err error
+
+	u, _ := url.Parse("http://localhost:9200")
+
+	transport, _ := estransport.New(estransport.Config{
+		URLs: []*url.URL{u},
+		CompressRequestBody: true,
+	})
+
+	indexName := "/shiny_new_index"
+
+	req, _ = http.NewRequest(http.MethodPut, indexName, nil)
+	res, err = transport.Perform(req)
+	if err != nil {
+		t.Fatalf("Unexpected error, cannot create index: %v", err)
+	}
+
+	req, _ = http.NewRequest(http.MethodGet, indexName, nil)
+	res, err = transport.Perform(req)
+	if err != nil {
+		t.Fatalf("Unexpected error, cannot find index: %v", err)
+	}
+
+	req, _ = http.NewRequest(
+		http.MethodPost,
+		strings.Join([]string{indexName, "/_doc"}, ""),
+		strings.NewReader(`{"solidPayload": 1}`),
+	)
+	req.Header.Set("Content-Type", "application/json")
+	res, err = transport.Perform(req)
+	if err != nil {
+		t.Fatalf("Unexpected error, cannot POST payload: %v", err)
+	}
+
+	if res.StatusCode != http.StatusCreated {
+		t.Fatalf("Unexpected StatusCode, expected 201, got: %v", res.StatusCode)
+	}
+
+	req, _ = http.NewRequest(http.MethodDelete, indexName, nil)
+	_, err = transport.Perform(req)
+	if err != nil {
+		t.Fatalf("Unexpected error, cannot DELETE %s: %v", indexName, err)
+	}
+}
\ No newline at end of file
diff --git a/estransport/estransport_internal_test.go b/estransport/estransport_internal_test.go
old mode 100755
new mode 100644
index 7738eebabd..9f8778d677
--- a/estransport/estransport_internal_test.go
+++ b/estransport/estransport_internal_test.go
@@ -1,19 +1,48 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package estransport
 
 import (
+	"bytes"
+	"compress/gzip"
+	"context"
 	"fmt"
+	"io"
+	"io/ioutil"
+	"math/rand"
 	"net/http"
 	"net/url"
+	"reflect"
 	"strings"
 	"testing"
+	"time"
 )
 
 var (
 	_ = fmt.Print
 )
 
+func init() {
+	rand.Seed(time.Now().Unix())
+}
+
 type mockTransp struct {
 	RoundTripFunc func(req *http.Request) (*http.Response, error)
 }
@@ -22,16 +51,22 @@ func (t *mockTransp) RoundTrip(req *http.Request) (*http.Response, error) {
 	return t.RoundTripFunc(req)
 }
 
+type mockNetError struct{ error }
+
+func (e *mockNetError) Timeout() bool   { return false }
+func (e *mockNetError) Temporary() bool { return false }
+
 func TestTransport(t *testing.T) {
 	t.Run("Interface", func(t *testing.T) {
-		var _ Interface = New(Config{})
-		var _ http.RoundTripper = New(Config{}).transport
+		tp, _ := New(Config{})
+		var _ Interface = tp
+		var _ http.RoundTripper = tp.transport
 	})
 
 	t.Run("Default", func(t *testing.T) {
-		tp := New(Config{})
+		tp, _ := New(Config{})
 		if tp.transport == nil {
-			t.Errorf("Expected the transport to not be nil")
+			t.Error("Expected the transport to not be nil")
 		}
 		if tp.transport != http.DefaultTransport {
 			t.Errorf("Expected the transport to be http.DefaultTransport, got: %T", tp.transport)
@@ -39,7 +74,7 @@ func TestTransport(t *testing.T) {
 	})
 
 	t.Run("Custom", func(t *testing.T) {
-		tp := New(Config{
+		tp, _ := New(Config{
 			URLs: []*url.URL{{}},
 			Transport: &mockTransp{
 				RoundTripFunc: func(req *http.Request) (*http.Response, error) { return &http.Response{Status: "MOCK"}, nil },
@@ -57,10 +92,184 @@ func TestTransport(t *testing.T) {
 	})
 }
 
+func TestTransportConfig(t *testing.T) {
+	t.Run("Defaults", func(t *testing.T) {
+		tp, _ := New(Config{})
+
+		if !reflect.DeepEqual(tp.retryOnStatus, []int{502, 503, 504}) {
+			t.Errorf("Unexpected retryOnStatus: %v", tp.retryOnStatus)
+		}
+
+		if tp.disableRetry {
+			t.Errorf("Unexpected disableRetry: %v", tp.disableRetry)
+		}
+
+		if tp.enableRetryOnTimeout {
+			t.Errorf("Unexpected enableRetryOnTimeout: %v", tp.enableRetryOnTimeout)
+		}
+
+		if tp.maxRetries != 3 {
+			t.Errorf("Unexpected maxRetries: %v", tp.maxRetries)
+		}
+
+		if tp.compressRequestBody {
+			t.Errorf("Unexpected compressRequestBody: %v", tp.compressRequestBody)
+		}
+	})
+
+	t.Run("Custom", func(t *testing.T) {
+		tp, _ := New(Config{
+			RetryOnStatus:        []int{404, 408},
+			DisableRetry:         true,
+			EnableRetryOnTimeout: true,
+			MaxRetries:           5,
+			CompressRequestBody:  true,
+		})
+
+		if !reflect.DeepEqual(tp.retryOnStatus, []int{404, 408}) {
+			t.Errorf("Unexpected retryOnStatus: %v", tp.retryOnStatus)
+		}
+
+		if !tp.disableRetry {
+			t.Errorf("Unexpected disableRetry: %v", tp.disableRetry)
+		}
+
+		if !tp.enableRetryOnTimeout {
+			t.Errorf("Unexpected enableRetryOnTimeout: %v", tp.enableRetryOnTimeout)
+		}
+
+		if tp.maxRetries != 5 {
+			t.Errorf("Unexpected maxRetries: %v", tp.maxRetries)
+		}
+
+		if !tp.compressRequestBody {
+			t.Errorf("Unexpected compressRequestBody: %v", tp.compressRequestBody)
+		}
+	})
+}
+
+func TestTransportConnectionPool(t *testing.T) {
+	t.Run("Single URL", func(t *testing.T) {
+		tp, _ := New(Config{URLs: []*url.URL{{Scheme: "http", Host: "foo1"}}})
+
+		if _, ok := tp.pool.(*singleConnectionPool); !ok {
+			t.Errorf("Expected connection to be singleConnectionPool, got: %T", tp)
+		}
+
+		conn, err := tp.pool.Next()
+		if err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		if conn.URL.String() != "http://foo1" {
+			t.Errorf("Unexpected URL, want=http://foo1, got=%s", conn.URL)
+		}
+	})
+
+	t.Run("Two URLs", func(t *testing.T) {
+		var (
+			conn *Connection
+			err  error
+		)
+
+		tp, _ := New(Config{URLs: []*url.URL{
+			{Scheme: "http", Host: "foo1"},
+			{Scheme: "http", Host: "foo2"},
+		}})
+
+		if _, ok := tp.pool.(*statusConnectionPool); !ok {
+			t.Errorf("Expected connection to be statusConnectionPool, got: %T", tp)
+		}
+
+		conn, err = tp.pool.Next()
+		if err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+		if conn.URL.String() != "http://foo1" {
+			t.Errorf("Unexpected URL, want=foo1, got=%s", conn.URL)
+		}
+
+		conn, err = tp.pool.Next()
+		if err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+		if conn.URL.String() != "http://foo2" {
+			t.Errorf("Unexpected URL, want=http://foo2, got=%s", conn.URL)
+		}
+
+		conn, err = tp.pool.Next()
+		if err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+		if conn.URL.String() != "http://foo1" {
+			t.Errorf("Unexpected URL, want=http://foo1, got=%s", conn.URL)
+		}
+	})
+}
+
+type CustomConnectionPool struct {
+	urls []*url.URL
+}
+
+// Next returns a random connection.
+func (cp *CustomConnectionPool) Next() (*Connection, error) {
+	u := cp.urls[rand.Intn(len(cp.urls))]
+	return &Connection{URL: u}, nil
+}
+
+func (cp *CustomConnectionPool) OnFailure(c *Connection) error {
+	var index = -1
+	for i, u := range cp.urls {
+		if u == c.URL {
+			index = i
+		}
+	}
+	if index > -1 {
+		cp.urls = append(cp.urls[:index], cp.urls[index+1:]...)
+		return nil
+	}
+	return fmt.Errorf("connection not found")
+}
+func (cp *CustomConnectionPool) OnSuccess(c *Connection) error { return nil }
+func (cp *CustomConnectionPool) URLs() []*url.URL              { return cp.urls }
+
+func TestTransportCustomConnectionPool(t *testing.T) {
+	t.Run("Run", func(t *testing.T) {
+		tp, _ := New(Config{
+			ConnectionPoolFunc: func(conns []*Connection, selector Selector) ConnectionPool {
+				return &CustomConnectionPool{
+					urls: []*url.URL{
+						{Scheme: "http", Host: "custom1"},
+						{Scheme: "http", Host: "custom2"},
+					},
+				}
+			},
+		})
+
+		if _, ok := tp.pool.(*CustomConnectionPool); !ok {
+			t.Fatalf("Unexpected connection pool, want=CustomConnectionPool, got=%T", tp.pool)
+		}
+
+		conn, err := tp.pool.Next()
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+		if conn.URL == nil {
+			t.Errorf("Empty connection URL: %+v", conn)
+		}
+		if err := tp.pool.OnFailure(conn); err != nil {
+			t.Errorf("Error removing the %q connection: %s", conn.URL, err)
+		}
+		if len(tp.pool.URLs()) != 1 {
+			t.Errorf("Unexpected number of connections in pool: %q", tp.pool)
+		}
+	})
+}
+
 func TestTransportPerform(t *testing.T) {
 	t.Run("Executes", func(t *testing.T) {
 		u, _ := url.Parse("https://foo.com/bar")
-		tp := New(Config{
+		tp, _ := New(Config{
 			URLs: []*url.URL{u},
 			Transport: &mockTransp{
 				RoundTripFunc: func(req *http.Request) (*http.Response, error) { return &http.Response{Status: "MOCK"}, nil },
@@ -80,10 +289,10 @@ func TestTransportPerform(t *testing.T) {
 
 	t.Run("Sets URL", func(t *testing.T) {
 		u, _ := url.Parse("https://foo.com/bar")
-		tp := New(Config{URLs: []*url.URL{u}})
+		tp, _ := New(Config{URLs: []*url.URL{u}})
 
 		req, _ := http.NewRequest("GET", "/abc", nil)
-		tp.setURL(u, req)
+		tp.setReqURL(u, req)
 
 		expected := "https://foo.com/bar/abc"
 
@@ -94,14 +303,14 @@ func TestTransportPerform(t *testing.T) {
 
 	t.Run("Sets HTTP Basic Auth from URL", func(t *testing.T) {
 		u, _ := url.Parse("https://foo:bar@example.com")
-		tp := New(Config{URLs: []*url.URL{u}})
+		tp, _ := New(Config{URLs: []*url.URL{u}})
 
 		req, _ := http.NewRequest("GET", "/", nil)
-		tp.setBasicAuth(u, req)
+		tp.setReqAuth(u, req)
 
 		username, password, ok := req.BasicAuth()
 		if !ok {
-			t.Errorf("Expected the request to have Basic Auth set")
+			t.Error("Expected the request to have Basic Auth set")
 		}
 
 		if username != "foo" || password != "bar" {
@@ -111,10 +320,10 @@ func TestTransportPerform(t *testing.T) {
 
 	t.Run("Sets HTTP Basic Auth from configuration", func(t *testing.T) {
 		u, _ := url.Parse("http://example.com")
-		tp := New(Config{URLs: []*url.URL{u}, Username: "foo", Password: "bar"})
+		tp, _ := New(Config{URLs: []*url.URL{u}, Username: "foo", Password: "bar"})
 
 		req, _ := http.NewRequest("GET", "/", nil)
-		tp.setBasicAuth(u, req)
+		tp.setReqAuth(u, req)
 
 		username, password, ok := req.BasicAuth()
 		if !ok {
@@ -126,20 +335,114 @@ func TestTransportPerform(t *testing.T) {
 		}
 	})
 
+	t.Run("Sets APIKey Authentication from configuration", func(t *testing.T) {
+		u, _ := url.Parse("http://example.com")
+		tp, _ := New(Config{URLs: []*url.URL{u}, APIKey: "Zm9vYmFy"}) // foobar
+
+		req, _ := http.NewRequest("GET", "/", nil)
+		tp.setReqAuth(u, req)
+
+		value := req.Header.Get("Authorization")
+		if value == "" {
+			t.Errorf("Expected the request to have the Authorization header set")
+		}
+
+		if value != "APIKey Zm9vYmFy" {
+			t.Errorf(`Unexpected value for Authorization: want="APIKey Zm9vYmFy", got="%s"`, value)
+		}
+	})
+
+	t.Run("Sets APIKey Authentication over ServiceToken", func(t *testing.T) {
+		u, _ := url.Parse("http://example.com")
+		tp, _ := New(Config{URLs: []*url.URL{u}, APIKey: "Zm9vYmFy", ServiceToken: "AAEAAWVs"}) // foobar
+
+		req, _ := http.NewRequest("GET", "/", nil)
+		tp.setReqAuth(u, req)
+
+		value := req.Header.Get("Authorization")
+		if value == "" {
+			t.Errorf("Expected the request to have the Authorization header set")
+		}
+
+		if value != "APIKey Zm9vYmFy" {
+			t.Errorf(`Unexpected value for Authorization: want="APIKey Zm9vYmFy", got="%s"`, value)
+		}
+	})
+
+	t.Run("Sets ServiceToken Authentication from configuration", func(t *testing.T) {
+		u, _ := url.Parse("http://example.com")
+		tp, _ := New(Config{URLs: []*url.URL{u}, ServiceToken: "AAEAAWVs"})
+
+		req, _ := http.NewRequest("GET", "/", nil)
+		tp.setReqAuth(u, req)
+
+		value := req.Header.Get("Authorization")
+		if value == "" {
+			t.Errorf("Expected the request to have the Authorization header set")
+		}
+
+		if value != "Bearer AAEAAWVs" {
+			t.Errorf(`Unexpected value for Authorization: want="Bearer AAEAAWVs", got="%s"`, value)
+		}
+	})
+
 	t.Run("Sets UserAgent", func(t *testing.T) {
 		u, _ := url.Parse("http://example.com")
-		tp := New(Config{URLs: []*url.URL{u}})
+		tp, _ := New(Config{URLs: []*url.URL{u}})
 
 		req, _ := http.NewRequest("GET", "/abc", nil)
-		tp.setUserAgent(req)
+		tp.setReqUserAgent(req)
 
 		if !strings.HasPrefix(req.UserAgent(), "go-elasticsearch") {
 			t.Errorf("Unexpected user agent: %s", req.UserAgent())
 		}
 	})
 
+	t.Run("Overwrites UserAgent", func(t *testing.T) {
+		u, _ := url.Parse("http://example.com")
+
+		tp, _ := New(Config{URLs: []*url.URL{u}, Header: http.Header{
+			userAgentHeader: []string{"Elastic-Fleet-Server/7.11.1 (darwin; amd64; Go 1.16.6)"},
+		}})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+		tp.setReqUserAgent(req)
+
+		if !strings.HasPrefix(req.UserAgent(), "Elastic-Fleet-Server") {
+			t.Errorf("Unexpected user agent: %s", req.UserAgent())
+		}
+	})
+
+	t.Run("Sets global HTTP request headers", func(t *testing.T) {
+		hdr := http.Header{}
+		hdr.Set("X-Foo", "bar")
+
+		tp, _ := New(Config{Header: hdr})
+
+		{
+			// Set the global HTTP header
+			req, _ := http.NewRequest("GET", "/abc", nil)
+			tp.setReqGlobalHeader(req)
+
+			if req.Header.Get("X-Foo") != "bar" {
+				t.Errorf("Unexpected global HTTP request header value: %s", req.Header.Get("X-Foo"))
+			}
+		}
+
+		{
+			// Do NOT overwrite an existing request header
+			req, _ := http.NewRequest("GET", "/abc", nil)
+			req.Header.Set("X-Foo", "baz")
+			tp.setReqGlobalHeader(req)
+
+			if req.Header.Get("X-Foo") != "baz" {
+				t.Errorf("Unexpected global HTTP request header value: %s", req.Header.Get("X-Foo"))
+			}
+		}
+	})
+
 	t.Run("Error No URL", func(t *testing.T) {
-		tp := New(Config{
+		tp, _ := New(Config{
 			URLs: []*url.URL{},
 			Transport: &mockTransp{
 				RoundTripFunc: func(req *http.Request) (*http.Response, error) { return &http.Response{Status: "MOCK"}, nil },
@@ -147,108 +450,393 @@ func TestTransportPerform(t *testing.T) {
 
 		req, _ := http.NewRequest("GET", "/abc", nil)
 
-		res, err := tp.Perform(req)
-		if err.Error() != "cannot get URL: No URL available" {
-			t.Fatalf("Expected error `cannot get URL`: but got error %v, response %v", err, res)
+		_, err := tp.Perform(req)
+		if err.Error() != `cannot get connection: no connection available` {
+			t.Fatalf("Expected error `cannot get URL`: but got error %q", err)
 		}
 	})
 }
 
-func TestTransportSelector(t *testing.T) {
-	t.Run("Nil value", func(t *testing.T) {
-		tp := New(Config{URLs: []*url.URL{nil}})
+func TestTransportPerformRetries(t *testing.T) {
+	t.Run("Retry request on network error and return the response", func(t *testing.T) {
+		var (
+			i       int
+			numReqs = 2
+		)
 
-		u, err := tp.selector.Select()
-		if err == nil {
-			t.Errorf("Expected error, but got %s", u)
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					if i == numReqs {
+						fmt.Print(": OK\n")
+						return &http.Response{Status: "OK"}, nil
+					}
+					fmt.Print(": ERR\n")
+					return nil, &mockNetError{error: fmt.Errorf("Mock network error (%d)", i)}
+				},
+			}})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if res.Status != "OK" {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		if i != numReqs {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
 		}
 	})
 
-	t.Run("No URL", func(t *testing.T) {
-		tp := New(Config{})
+	t.Run("Retry request on EOF error and return the response", func(t *testing.T) {
+		var (
+			i       int
+			numReqs = 2
+		)
+
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					if i == numReqs {
+						fmt.Print(": OK\n")
+						return &http.Response{Status: "OK"}, nil
+					}
+					fmt.Print(": ERR\n")
+					return nil, io.EOF
+				},
+			}})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if res.Status != "OK" {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		if i != numReqs {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
+		}
+	})
+
+	t.Run("Retry request on 5xx response and return new response", func(t *testing.T) {
+		var (
+			i       int
+			numReqs = 2
+		)
+
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					if i == numReqs {
+						fmt.Print(": 200\n")
+						return &http.Response{StatusCode: 200}, nil
+					}
+					fmt.Print(": 502\n")
+					return &http.Response{StatusCode: 502}, nil
+				},
+			}})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if res.StatusCode != 200 {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		if i != numReqs {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
+		}
+	})
+
+	t.Run("Close response body for a 5xx response", func(t *testing.T) {
+		var (
+			i       int
+			numReqs = 5
+		)
+
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs:       []*url.URL{u, u, u},
+			MaxRetries: numReqs,
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					fmt.Print(": 502\n")
+					body := ioutil.NopCloser(strings.NewReader(`MOCK`))
+					return &http.Response{StatusCode: 502, Body: body}, nil
+				},
+			}})
+
+		req, _ := http.NewRequest("GET", "/", nil)
+
+		res, err := tp.Perform(req)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if i != numReqs+1 {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
+		}
+
+		if res.StatusCode != 502 {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		resBody, _ := ioutil.ReadAll(res.Body)
+		res.Body.Close()
+
+		if string(resBody) != "MOCK" {
+			t.Errorf("Unexpected body, want=MOCK, got=%s", resBody)
+		}
+	})
+
+	t.Run("Retry request and return error when max retries exhausted", func(t *testing.T) {
+		var (
+			i       int
+			numReqs = 3
+		)
+
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					fmt.Print(": ERR\n")
+					return nil, &mockNetError{error: fmt.Errorf("Mock network error (%d)", i)}
+				},
+			}})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
 
-		u, err := tp.selector.Select()
 		if err == nil {
-			t.Errorf("Expected error, but got %s", u)
+			t.Fatalf("Expected error, got: %v", err)
+		}
+
+		if res != nil {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		// Should be initial HTTP request + 3 retries
+		if i != numReqs+1 {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
 		}
 	})
 
-	t.Run("Single URL", func(t *testing.T) {
-		tp := New(Config{URLs: []*url.URL{{Scheme: "http", Host: "localhost:9200"}}})
+	t.Run("Reset request body during retry", func(t *testing.T) {
+		var bodies []string
+		u, _ := url.Parse("https://foo.com/bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					body, err := ioutil.ReadAll(req.Body)
+					if err != nil {
+						panic(err)
+					}
+					bodies = append(bodies, string(body))
+					return &http.Response{Status: "MOCK", StatusCode: 502}, nil
+				},
+			}},
+		)
 
-		for i := 0; i < 7; i++ {
-			u, err := tp.selector.Select()
-			if err != nil {
-				t.Errorf("Unexpected error: %s", err)
-			}
+		req, _ := http.NewRequest("POST", "/abc", strings.NewReader("FOOBAR"))
+		res, err := tp.Perform(req)
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+		_ = res
 
-			if u.String() != "http://localhost:9200" {
-				t.Errorf("Unexpected URL, want=http://localhost:9200, got=%s", u)
+		if n := len(bodies); n != 4 {
+			t.Fatalf("expected 4 requests, got %d", n)
+		}
+		for i, body := range bodies {
+			if body != "FOOBAR" {
+				t.Fatalf("request %d body: expected %q, got %q", i, "FOOBAR", body)
 			}
 		}
 	})
 
-	t.Run("Two URLs", func(t *testing.T) {
-		var u *url.URL
+	t.Run("Don't retry request on regular error", func(t *testing.T) {
+		var i int
 
-		tp := New(Config{URLs: []*url.URL{
-			{Scheme: "http", Host: "localhost:9200"},
-			{Scheme: "http", Host: "localhost:9201"},
-		}})
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					fmt.Print(": ERR\n")
+					return nil, fmt.Errorf("Mock regular error (%d)", i)
+				},
+			}})
 
-		u, _ = tp.selector.Select()
-		if u.String() != "http://localhost:9200" {
-			t.Errorf("Unexpected URL, want=http://localhost:9200, got=%s", u)
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
+
+		if err == nil {
+			t.Fatalf("Expected error, got: %v", err)
 		}
 
-		u, _ = tp.selector.Select()
-		if u.String() != "http://localhost:9201" {
-			t.Errorf("Unexpected URL, want=http://localhost:9201, got=%s", u)
+		if res != nil {
+			t.Errorf("Unexpected response: %+v", res)
 		}
 
-		u, _ = tp.selector.Select()
-		if u.String() != "http://localhost:9200" {
-			t.Errorf("Unexpected URL, want=http://localhost:9200, got=%s", u)
+		if i != 1 {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", 1, i)
 		}
 	})
 
-	t.Run("Three URLs", func(t *testing.T) {
-		tp := New(Config{URLs: []*url.URL{
-			{Scheme: "http", Host: "localhost:9200"},
-			{Scheme: "http", Host: "localhost:9201"},
-			{Scheme: "http", Host: "localhost:9202"},
-		}})
+	t.Run("Don't retry request when retries are disabled", func(t *testing.T) {
+		var i int
 
-		var expected string
-		for i := 0; i < 11; i++ {
-			u, err := tp.selector.Select()
-			// fmt.Printf("> %s\n", u)
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					fmt.Print(": ERR\n")
+					return nil, &mockNetError{error: fmt.Errorf("Mock network error (%d)", i)}
+				},
+			},
+			DisableRetry: true,
+		})
 
-			if err != nil {
-				t.Errorf("Unexpected error: %s", err)
-			}
+		req, _ := http.NewRequest("GET", "/abc", nil)
+		tp.Perform(req)
 
-			switch i % 3 {
-			case 0:
-				expected = "http://localhost:9200"
-			case 1:
-				expected = "http://localhost:9201"
-			case 2:
-				expected = "http://localhost:9202"
-			default:
-				t.Fatalf("Unexpected i %% 3: %d", i%3)
-			}
+		if i != 1 {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", 1, i)
+		}
+	})
 
-			if u.String() != expected {
-				t.Errorf("Unexpected URL, want=%s, got=%s", expected, u)
-			}
+	t.Run("Delay the retry with a backoff function", func(t *testing.T) {
+		var (
+			i                int
+			numReqs          = 4
+			start            = time.Now()
+			expectedDuration = time.Duration((numReqs-1)*100) * time.Millisecond
+		)
+
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			MaxRetries: numReqs,
+			URLs:       []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					fmt.Printf("Request #%d", i)
+					if i == numReqs {
+						fmt.Print(": OK\n")
+						return &http.Response{Status: "OK"}, nil
+					}
+					fmt.Print(": ERR\n")
+					return nil, &mockNetError{error: fmt.Errorf("Mock network error (%d)", i)}
+				},
+			},
+
+			// A simple incremental backoff function
+			//
+			RetryBackoff: func(i int) time.Duration {
+				d := time.Duration(i) * 100 * time.Millisecond
+				fmt.Printf("Attempt: %d | Sleeping for %s...\n", i, d)
+				return d
+			},
+		})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+
+		res, err := tp.Perform(req)
+		end := time.Since(start)
+
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if res.Status != "OK" {
+			t.Errorf("Unexpected response: %+v", res)
+		}
+
+		if i != numReqs {
+			t.Errorf("Unexpected number of requests, want=%d, got=%d", numReqs, i)
+		}
+
+		if end < expectedDuration {
+			t.Errorf("Unexpected duration, want=>%s, got=%s", expectedDuration, end)
+		}
+	})
+
+	t.Run("Delay the retry with retry on timeout and context deadline", func(t *testing.T) {
+		var i int
+		u, _ := url.Parse("http://foo.bar")
+		tp, _ := New(Config{
+			EnableRetryOnTimeout: true,
+			MaxRetries:           100,
+			RetryBackoff:         func(i int) time.Duration { return time.Hour },
+			URLs:                 []*url.URL{u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					i++
+					<-req.Context().Done()
+					return nil, req.Context().Err()
+				},
+			},
+		})
+
+		req, _ := http.NewRequest("GET", "/abc", nil)
+		ctx, cancel := context.WithTimeout(req.Context(), 50*time.Millisecond)
+		defer cancel()
+		req = req.WithContext(ctx)
+
+		_, err := tp.Perform(req)
+		if err != context.DeadlineExceeded {
+			t.Fatalf("expected context.DeadlineExceeded, got %s", err)
+		}
+		if i != 1 {
+			t.Fatalf("unexpected number of requests: expected 1, got got %d", i)
 		}
 	})
 }
 
 func TestURLs(t *testing.T) {
 	t.Run("Returns URLs", func(t *testing.T) {
-		tp := New(Config{URLs: []*url.URL{
+		tp, _ := New(Config{URLs: []*url.URL{
 			{Scheme: "http", Host: "localhost:9200"},
 			{Scheme: "http", Host: "localhost:9201"},
 		}})
@@ -267,3 +855,257 @@ func TestVersion(t *testing.T) {
 		t.Error("Version is empty")
 	}
 }
+
+func TestMetaHeader(t *testing.T) {
+	t.Run("X-Elastic-Client-Meta header should be present by default", func(t *testing.T) {
+		u := &url.URL{Scheme: "http", Host: "foo:9200"}
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					return &http.Response{Status: "OK"}, nil
+				},
+			},
+		})
+
+		req, _ := http.NewRequest("GET", "/", nil)
+
+		tp.Perform(req)
+
+		headerValue := req.Header.Get("X-Elastic-Client-Meta")
+		fmt.Println(headerValue)
+		if headerValue != initMetaHeader() {
+			t.Errorf("Meta header should be present, want: %s, got : %s",
+				initMetaHeader(),
+				headerValue,
+			)
+		}
+	})
+	t.Run("X-Elastic-Client-Meta header should be disabled by config", func(t *testing.T) {
+		u := &url.URL{Scheme: "http", Host: "foo:9200"}
+		tp, _ := New(Config{
+			URLs: []*url.URL{u, u, u},
+			Transport: &mockTransp{
+				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+					return &http.Response{Status: "OK"}, nil
+				},
+			},
+			DisableMetaHeader: true,
+		})
+
+		req, _ := http.NewRequest("GET", "/", nil)
+
+		_, _ = tp.Perform(req)
+
+		headerValue := req.Header.Get("X-Elastic-Client-Meta")
+		if headerValue != "" {
+			t.Errorf("Meta header should be empty, got: %s", headerValue)
+		}
+	})
+}
+
+func TestMaxRetries(t *testing.T) {
+	tests := []struct {
+		name              string
+		maxRetries        int
+		disableRetry      bool
+		expectedCallCount int
+	}{
+		{
+			name:              "MaxRetries Active set to default",
+			disableRetry:      false,
+			expectedCallCount: 4,
+		},
+		{
+			name:              "MaxRetries Active set to 1",
+			maxRetries:        1,
+			disableRetry:      false,
+			expectedCallCount: 2,
+		},
+		{
+			name:              "Max Retries Active set to 2",
+			maxRetries:        2,
+			disableRetry:      false,
+			expectedCallCount: 3,
+		},
+		{
+			name:              "Max Retries Active set to 3",
+			maxRetries:        3,
+			disableRetry:      false,
+			expectedCallCount: 4,
+		},
+		{
+			name:              "MaxRetries Inactive set to 0",
+			maxRetries:        0,
+			disableRetry:      true,
+			expectedCallCount: 1,
+		},
+		{
+			name:              "MaxRetries Inactive set to 3",
+			maxRetries:        3,
+			disableRetry:      true,
+			expectedCallCount: 1,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			var callCount int
+			c, _ := New(Config{
+				URLs: []*url.URL{{}},
+				Transport: &mockTransp{
+					RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+						callCount++
+						return &http.Response{
+							StatusCode: http.StatusBadGateway,
+							Status:     "MOCK",
+						}, nil
+					},
+				},
+				MaxRetries:   test.maxRetries,
+				DisableRetry: test.disableRetry,
+			})
+
+			c.Perform(&http.Request{URL: &url.URL{}, Header: make(http.Header)}) // errcheck ignore
+
+			if test.expectedCallCount != callCount {
+				t.Errorf("Bad retry call count, got : %d, want : %d", callCount, test.expectedCallCount)
+			}
+		})
+	}
+}
+
+func TestCompatibilityHeader(t *testing.T) {
+	tests := []struct {
+		name                string
+		compatibilityHeader bool
+		bodyPresent         bool
+		expectsHeader       []string
+	}{
+		{
+			name:                "Compatibility header disabled",
+			compatibilityHeader: false,
+			bodyPresent:         false,
+			expectsHeader:       []string{"application/json"},
+		},
+		{
+			name:                "Compatibility header enabled",
+			compatibilityHeader: true,
+			bodyPresent:         false,
+			expectsHeader:       []string{"application/vnd.elasticsearch+json;compatible-with=7"},
+		},
+		{
+			name:                "Compatibility header enabled with body",
+			compatibilityHeader: true,
+			bodyPresent:         true,
+			expectsHeader:       []string{"application/vnd.elasticsearch+json;compatible-with=7"},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			compatibilityHeader = test.compatibilityHeader
+
+			c, _ := New(Config{
+				URLs: []*url.URL{{}},
+				Transport: &mockTransp{
+					RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+						if test.compatibilityHeader {
+							if !reflect.DeepEqual(req.Header["Accept"], test.expectsHeader) {
+								t.Errorf("Compatibility header enabled but header is, not in request headers, got: %s, want: %s", req.Header["Accept"], test.expectsHeader)
+							}
+						}
+						if test.bodyPresent {
+							if !reflect.DeepEqual(req.Header["Content-Type"], test.expectsHeader) {
+								t.Errorf("Compatibility header with Body enabled, not in request headers, got: %s, want: %s", req.Header["Content-Type"], test.expectsHeader)
+							}
+						}
+
+						return &http.Response{
+							StatusCode: http.StatusOK,
+							Status:     "MOCK",
+						}, nil
+					},
+				},
+			})
+
+			req := &http.Request{URL: &url.URL{}, Header: make(http.Header)}
+			if test.bodyPresent {
+				req.Body = ioutil.NopCloser(strings.NewReader("{}"))
+			}
+
+			_, _ = c.Perform(req)
+
+			compatibilityHeader = false
+		})
+	}
+}
+
+func TestRequestCompression(t *testing.T) {
+
+	tests := []struct {
+		name            string
+		compressionFlag bool
+		inputBody       string
+	}{
+		{
+			name:            "Uncompressed",
+			compressionFlag: false,
+			inputBody:       "elasticsearch",
+		},
+		{
+			name:            "Compressed",
+			compressionFlag: true,
+			inputBody:       "elasticsearch",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			tp, _ := New(Config{
+				URLs:                []*url.URL{{}},
+				CompressRequestBody: test.compressionFlag,
+				Transport: &mockTransp{
+					RoundTripFunc: func(req *http.Request) (*http.Response, error) {
+						if req.Body == nil || req.Body == http.NoBody {
+							return nil, fmt.Errorf("unexpected body: %v", req.Body)
+						}
+
+						var buf bytes.Buffer
+						buf.ReadFrom(req.Body)
+
+						if req.ContentLength != int64(buf.Len()) {
+							return nil, fmt.Errorf("mismatched Content-Length: %d vs actual %d", req.ContentLength, buf.Len())
+						}
+
+						if test.compressionFlag {
+							var unBuf bytes.Buffer
+							zr, err := gzip.NewReader(&buf)
+							if err != nil {
+								return nil, fmt.Errorf("decompression error: %v", err)
+							}
+							unBuf.ReadFrom(zr)
+							buf = unBuf
+						}
+
+						if buf.String() != test.inputBody {
+							return nil, fmt.Errorf("unexpected body: %s", buf.String())
+						}
+
+						return &http.Response{Status: "MOCK"}, nil
+					},
+				},
+			})
+
+			req, _ := http.NewRequest("POST", "/abc", bytes.NewBufferString(test.inputBody))
+
+			res, err := tp.Perform(req)
+			if err != nil {
+				t.Fatalf("Unexpected error: %s", err)
+			}
+
+			if res.Status != "MOCK" {
+				t.Errorf("Unexpected response: %+v", res)
+			}
+		})
+	}
+}
diff --git a/estransport/logger.go b/estransport/logger.go
index 55d35e9a32..fb368c30ad 100644
--- a/estransport/logger.go
+++ b/estransport/logger.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package estransport
 
 import (
@@ -14,6 +31,8 @@ import (
 	"time"
 )
 
+var debugLogger DebuggingLogger
+
 // Logger defines an interface for logging request and response.
 //
 type Logger interface {
@@ -26,6 +45,13 @@ type Logger interface {
 	ResponseBodyEnabled() bool
 }
 
+// DebuggingLogger defines the interface for a debugging logger.
+//
+type DebuggingLogger interface {
+	Log(a ...interface{}) error
+	Logf(format string, a ...interface{}) error
+}
+
 // TextLogger prints the log message in plain text.
 //
 type TextLogger struct {
@@ -58,6 +84,12 @@ type JSONLogger struct {
 	EnableResponseBody bool
 }
 
+// debuggingLogger prints debug messages as plain text.
+//
+type debuggingLogger struct {
+	Output io.Writer
+}
+
 // LogRoundTrip prints the information about request and response.
 //
 func (l *TextLogger) LogRoundTrip(req *http.Request, res *http.Response, err error, start time.Time, dur time.Duration) error {
@@ -70,7 +102,12 @@ func (l *TextLogger) LogRoundTrip(req *http.Request, res *http.Response, err err
 	)
 	if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody {
 		var buf bytes.Buffer
-		buf.ReadFrom(req.Body)
+		if req.GetBody != nil {
+			b, _ := req.GetBody()
+			buf.ReadFrom(b)
+		} else {
+			buf.ReadFrom(req.Body)
+		}
 		logBodyAsText(l.Output, &buf, ">")
 	}
 	if l.ResponseBodyEnabled() && res != nil && res.Body != nil && res.Body != http.NoBody {
@@ -130,7 +167,12 @@ func (l *ColorLogger) LogRoundTrip(req *http.Request, res *http.Response, err er
 
 	if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody {
 		var buf bytes.Buffer
-		buf.ReadFrom(req.Body)
+		if req.GetBody != nil {
+			b, _ := req.GetBody()
+			buf.ReadFrom(b)
+		} else {
+			buf.ReadFrom(req.Body)
+		}
 		fmt.Fprint(l.Output, "\x1b[2m")
 		logBodyAsText(l.Output, &buf, "       »")
 		fmt.Fprint(l.Output, "\x1b[0m")
@@ -207,7 +249,12 @@ func (l *CurlLogger) LogRoundTrip(req *http.Request, res *http.Response, err err
 
 	if req != nil && req.Body != nil && req.Body != http.NoBody {
 		var buf bytes.Buffer
-		buf.ReadFrom(req.Body)
+		if req.GetBody != nil {
+			b, _ := req.GetBody()
+			buf.ReadFrom(b)
+		} else {
+			buf.ReadFrom(req.Body)
+		}
 
 		b.Grow(buf.Len())
 		b.WriteString(" -d \\\n'")
@@ -310,7 +357,12 @@ func (l *JSONLogger) LogRoundTrip(req *http.Request, res *http.Response, err err
 	appendQuote(req.Method)
 	if l.RequestBodyEnabled() && req != nil && req.Body != nil && req.Body != http.NoBody {
 		var buf bytes.Buffer
-		buf.ReadFrom(req.Body)
+		if req.GetBody != nil {
+			b, _ := req.GetBody()
+			buf.ReadFrom(b)
+		} else {
+			buf.ReadFrom(req.Body)
+		}
 
 		b.Grow(buf.Len() + 8)
 		b.WriteString(`,"body":`)
@@ -351,6 +403,20 @@ func (l *JSONLogger) RequestBodyEnabled() bool { return l.EnableRequestBody }
 // ResponseBodyEnabled returns true when the response body should be logged.
 func (l *JSONLogger) ResponseBodyEnabled() bool { return l.EnableResponseBody }
 
+// Log prints the arguments to output in default format.
+//
+func (l *debuggingLogger) Log(a ...interface{}) error {
+	_, err := fmt.Fprint(l.Output, a...)
+	return err
+}
+
+// Logf prints formats the arguments and prints them to output.
+//
+func (l *debuggingLogger) Logf(format string, a ...interface{}) error {
+	_, err := fmt.Fprintf(l.Output, format, a...)
+	return err
+}
+
 func logBodyAsText(dst io.Writer, body io.Reader, prefix string) {
 	scanner := bufio.NewScanner(body)
 	for scanner.Scan() {
diff --git a/estransport/logger_benchmark_test.go b/estransport/logger_benchmark_test.go
index 226104fdc3..bc706a7fff 100644
--- a/estransport/logger_benchmark_test.go
+++ b/estransport/logger_benchmark_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package estransport_test
@@ -9,7 +26,7 @@ import (
 	"net/url"
 	"testing"
 
-	"github.com/elastic/go-elasticsearch/estransport"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
 )
 
 func BenchmarkTransportLogger(b *testing.B) {
@@ -17,8 +34,8 @@ func BenchmarkTransportLogger(b *testing.B) {
 
 	b.Run("Text", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			tp := estransport.New(estransport.Config{
-				URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 				Transport: newFakeTransport(b),
 				Logger:    &estransport.TextLogger{Output: ioutil.Discard},
 			})
@@ -33,8 +50,8 @@ func BenchmarkTransportLogger(b *testing.B) {
 
 	b.Run("Text-Body", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			tp := estransport.New(estransport.Config{
-				URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 				Transport: newFakeTransport(b),
 				Logger:    &estransport.TextLogger{Output: ioutil.Discard, EnableRequestBody: true, EnableResponseBody: true},
 			})
@@ -58,8 +75,8 @@ func BenchmarkTransportLogger(b *testing.B) {
 
 	b.Run("JSON", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			tp := estransport.New(estransport.Config{
-				URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 				Transport: newFakeTransport(b),
 				Logger:    &estransport.JSONLogger{Output: ioutil.Discard},
 			})
@@ -74,8 +91,8 @@ func BenchmarkTransportLogger(b *testing.B) {
 
 	b.Run("JSON-Body", func(b *testing.B) {
 		for i := 0; i < b.N; i++ {
-			tp := estransport.New(estransport.Config{
-				URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+			tp, _ := estransport.New(estransport.Config{
+				URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 				Transport: newFakeTransport(b),
 				Logger:    &estransport.JSONLogger{Output: ioutil.Discard, EnableRequestBody: true, EnableResponseBody: true},
 			})
diff --git a/estransport/logger_internal_test.go b/estransport/logger_internal_test.go
index fbf0211e25..5e5acb16d3 100644
--- a/estransport/logger_internal_test.go
+++ b/estransport/logger_internal_test.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build !integration
 
 package estransport
@@ -41,8 +58,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("Defaults", func(t *testing.T) {
 		var wg sync.WaitGroup
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			// Logger: ioutil.Discard,
 		})
@@ -55,7 +72,8 @@ func TestTransportLogger(t *testing.T) {
 				req, _ := http.NewRequest("GET", "/abc", nil)
 				_, err := tp.Perform(req)
 				if err != nil {
-					t.Fatalf("Unexpected error: %s", err)
+					t.Errorf("Unexpected error: %s", err)
+					return
 				}
 			}()
 		}
@@ -63,8 +81,8 @@ func TestTransportLogger(t *testing.T) {
 	})
 
 	t.Run("Nil", func(t *testing.T) {
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    nil,
 		})
@@ -77,8 +95,8 @@ func TestTransportLogger(t *testing.T) {
 	})
 
 	t.Run("No HTTP response", func(t *testing.T) {
-		tp := New(Config{
-			URLs: []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs: []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: &mockTransp{
 				RoundTripFunc: func(req *http.Request) (*http.Response, error) {
 					return nil, errors.New("Mock error")
@@ -88,17 +106,20 @@ func TestTransportLogger(t *testing.T) {
 		})
 
 		req, _ := http.NewRequest("GET", "/abc", nil)
-		_, err := tp.Perform(req)
+		res, err := tp.Perform(req)
 		if err == nil {
-			t.Fatalf("Expected error: %s", err)
+			t.Errorf("Expected error: %v", err)
+		}
+		if res != nil {
+			t.Errorf("Expected nil response, got: %v", err)
 		}
 	})
 
 	t.Run("Keep response body", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &TextLogger{Output: &dst, EnableRequestBody: true, EnableResponseBody: true},
 		})
@@ -128,8 +149,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("Text with body", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &TextLogger{Output: &dst, EnableRequestBody: true, EnableResponseBody: true},
 		})
@@ -173,8 +194,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("Color with body", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &ColorLogger{Output: &dst, EnableRequestBody: true, EnableResponseBody: true},
 		})
@@ -227,10 +248,11 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("Curl", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
-			Transport: newRoundTripper(),
-			Logger:    &CurlLogger{Output: &dst, EnableRequestBody: true, EnableResponseBody: true},
+		tp, _ := New(Config{
+			URLs:              []*url.URL{{Scheme: "http", Host: "foo"}},
+			Transport:         newRoundTripper(),
+			Logger:            &CurlLogger{Output: &dst, EnableRequestBody: true, EnableResponseBody: true},
+			DisableMetaHeader: true,
 		})
 
 		req, _ := http.NewRequest("GET", "/abc?q=a,b", nil)
@@ -248,7 +270,6 @@ func TestTransportLogger(t *testing.T) {
 
 		output := dst.String()
 		output = strings.TrimSuffix(output, "\n")
-		// fmt.Println(output)
 
 		lines := strings.Split(output, "\n")
 
@@ -264,8 +285,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("JSON", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &JSONLogger{Output: &dst},
 		})
@@ -301,8 +322,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("JSON with request body", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &JSONLogger{Output: &dst, EnableRequestBody: true},
 		})
@@ -344,8 +365,8 @@ func TestTransportLogger(t *testing.T) {
 	t.Run("Custom", func(t *testing.T) {
 		var dst strings.Builder
 
-		tp := New(Config{
-			URLs:      []*url.URL{&url.URL{Scheme: "http", Host: "foo"}},
+		tp, _ := New(Config{
+			URLs:      []*url.URL{{Scheme: "http", Host: "foo"}},
 			Transport: newRoundTripper(),
 			Logger:    &CustomLogger{Output: &dst},
 		})
@@ -423,6 +444,21 @@ func TestTransportLogger(t *testing.T) {
 	})
 }
 
+func TestDebuggingLogger(t *testing.T) {
+	logger := &debuggingLogger{Output: ioutil.Discard}
+
+	t.Run("Log", func(t *testing.T) {
+		if err := logger.Log("Foo"); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+	})
+	t.Run("Logf", func(t *testing.T) {
+		if err := logger.Logf("Foo %d", 1); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+	})
+}
+
 type CustomLogger struct {
 	Output io.Writer
 }
diff --git a/estransport/metaheader.go b/estransport/metaheader.go
new file mode 100644
index 0000000000..190c5a0f35
--- /dev/null
+++ b/estransport/metaheader.go
@@ -0,0 +1,81 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
+
+import (
+	"regexp"
+	"runtime"
+	"strings"
+)
+
+// HeaderClientMeta Key for the HTTP Header related to telemetry data sent with
+// each request to Elasticsearch.
+const HeaderClientMeta = "x-elastic-client-meta"
+
+var metaReVersion = regexp.MustCompile("([0-9.]+)(.*)")
+
+func initMetaHeader() string {
+	var b strings.Builder
+	var strippedGoVersion string
+	var strippedEsVersion string
+
+	strippedEsVersion = buildStrippedVersion(Version)
+	strippedGoVersion = buildStrippedVersion(runtime.Version())
+
+	var duos = [][]string{
+		{
+			"es",
+			strippedEsVersion,
+		},
+		{
+			"go",
+			strippedGoVersion,
+		},
+		{
+			"t",
+			strippedEsVersion,
+		},
+		{
+			"hc",
+			strippedGoVersion,
+		},
+	}
+
+	var arr []string
+	for _, duo := range duos {
+		arr = append(arr, strings.Join(duo, "="))
+	}
+	b.WriteString(strings.Join(arr, ","))
+
+	return b.String()
+}
+
+func buildStrippedVersion(version string) string {
+	v := metaReVersion.FindStringSubmatch(version)
+
+	if len(v) == 3 && !strings.Contains(version, "devel") {
+		switch {
+		case v[2] != "":
+			return v[1] + "p"
+		default:
+			return v[1]
+		}
+	}
+
+	return "0.0p"
+}
diff --git a/estransport/metaheader_test.go b/estransport/metaheader_test.go
new file mode 100644
index 0000000000..86b2bb036d
--- /dev/null
+++ b/estransport/metaheader_test.go
@@ -0,0 +1,115 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
+
+import (
+	"regexp"
+	"runtime"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/version"
+)
+
+var (
+	metaHeaderReValidation = regexp.MustCompile(`^[a-z]{1,}=[a-z0-9\.\-]{1,}(?:,[a-z]{1,}=[a-z0-9\.\-]+)*$`)
+)
+
+func Test_buildStrippedVersion(t *testing.T) {
+	type args struct {
+		version string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "Standard Go version",
+			args: args{version: "go1.16"},
+			want: "1.16",
+		},
+		{
+			name: "Rc Go version",
+			args: args{
+				version: "go1.16rc1",
+			},
+			want: "1.16p",
+		},
+		{
+			name: "Beta Go version (go1.16beta1 example)",
+			args: args{
+				version: "devel +2ff33f5e44 Thu Dec 17 16:03:19 2020 +0000",
+			},
+			want: "0.0p",
+		},
+		{
+			name: "Random mostly good Go version",
+			args: args{
+				version: "1.16",
+			},
+			want: "1.16",
+		},
+		{
+			name: "Client package version",
+			args: args{
+				version: "8.0.0",
+			},
+			want: "8.0.0",
+		},
+		{
+			name: "Client pre release version",
+			args: args{
+				version: "8.0.0-SNAPSHOT",
+			},
+			want: "8.0.0p",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := buildStrippedVersion(tt.args.version); got != tt.want {
+				t.Errorf("buildStrippedVersion() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_initMetaHeader(t *testing.T) {
+	esVersion := buildStrippedVersion(version.Client)
+	goVersion := buildStrippedVersion(runtime.Version())
+
+	tests := []struct {
+		name string
+		want string
+	}{
+		{
+			name: "Meta header generation",
+			want: "es=" + esVersion + ",go=" + goVersion + ",t=" + esVersion + ",hc=" + goVersion,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if metaHeader != tt.want {
+				t.Errorf("initMetaHeader() = %v, want %v", metaHeader, tt.want)
+			}
+			if valid := metaHeaderReValidation.Match([]byte(metaHeader)); valid != true {
+				t.Errorf("Metaheder doesn't validate regexp format validation, got : %s", metaHeader)
+			}
+		})
+	}
+}
diff --git a/estransport/metrics.go b/estransport/metrics.go
new file mode 100644
index 0000000000..591c262543
--- /dev/null
+++ b/estransport/metrics.go
@@ -0,0 +1,194 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package estransport
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// Measurable defines the interface for transports supporting metrics.
+//
+type Measurable interface {
+	Metrics() (Metrics, error)
+}
+
+// connectionable defines the interface for transports returning a list of connections.
+//
+type connectionable interface {
+	connections() []*Connection
+}
+
+// Metrics represents the transport metrics.
+//
+type Metrics struct {
+	Requests  int         `json:"requests"`
+	Failures  int         `json:"failures"`
+	Responses map[int]int `json:"responses"`
+
+	Connections []fmt.Stringer `json:"connections"`
+}
+
+// ConnectionMetric represents metric information for a connection.
+//
+type ConnectionMetric struct {
+	URL       string     `json:"url"`
+	Failures  int        `json:"failures,omitempty"`
+	IsDead    bool       `json:"dead,omitempty"`
+	DeadSince *time.Time `json:"dead_since,omitempty"`
+
+	Meta struct {
+		ID    string   `json:"id"`
+		Name  string   `json:"name"`
+		Roles []string `json:"roles"`
+	} `json:"meta"`
+}
+
+// metrics represents the inner state of metrics.
+//
+type metrics struct {
+	sync.RWMutex
+
+	requests  int
+	failures  int
+	responses map[int]int
+
+	connections []*Connection
+}
+
+// Metrics returns the transport metrics.
+//
+func (c *Client) Metrics() (Metrics, error) {
+	if c.metrics == nil {
+		return Metrics{}, errors.New("transport metrics not enabled")
+	}
+	c.metrics.RLock()
+	defer c.metrics.RUnlock()
+
+	if lockable, ok := c.pool.(sync.Locker); ok {
+		lockable.Lock()
+		defer lockable.Unlock()
+	}
+
+	m := Metrics{
+		Requests:  c.metrics.requests,
+		Failures:  c.metrics.failures,
+		Responses: c.metrics.responses,
+	}
+
+	if pool, ok := c.pool.(connectionable); ok {
+		for _, c := range pool.connections() {
+			c.Lock()
+
+			cm := ConnectionMetric{
+				URL:      c.URL.String(),
+				IsDead:   c.IsDead,
+				Failures: c.Failures,
+			}
+
+			if !c.DeadSince.IsZero() {
+				cm.DeadSince = &c.DeadSince
+			}
+
+			if c.ID != "" {
+				cm.Meta.ID = c.ID
+			}
+
+			if c.Name != "" {
+				cm.Meta.Name = c.Name
+			}
+
+			if len(c.Roles) > 0 {
+				cm.Meta.Roles = c.Roles
+			}
+
+			m.Connections = append(m.Connections, cm)
+			c.Unlock()
+		}
+	}
+
+	return m, nil
+}
+
+// String returns the metrics as a string.
+//
+func (m Metrics) String() string {
+	var (
+		i int
+		b strings.Builder
+	)
+	b.WriteString("{")
+
+	b.WriteString("Requests:")
+	b.WriteString(strconv.Itoa(m.Requests))
+
+	b.WriteString(" Failures:")
+	b.WriteString(strconv.Itoa(m.Failures))
+
+	if len(m.Responses) > 0 {
+		b.WriteString(" Responses: ")
+		b.WriteString("[")
+
+		for code, num := range m.Responses {
+			b.WriteString(strconv.Itoa(code))
+			b.WriteString(":")
+			b.WriteString(strconv.Itoa(num))
+			if i+1 < len(m.Responses) {
+				b.WriteString(", ")
+			}
+			i++
+		}
+		b.WriteString("]")
+	}
+
+	b.WriteString(" Connections: [")
+	for i, c := range m.Connections {
+		b.WriteString(c.String())
+		if i+1 < len(m.Connections) {
+			b.WriteString(", ")
+		}
+		i++
+	}
+	b.WriteString("]")
+
+	b.WriteString("}")
+	return b.String()
+}
+
+// String returns the connection information as a string.
+//
+func (cm ConnectionMetric) String() string {
+	var b strings.Builder
+	b.WriteString("{")
+	b.WriteString(cm.URL)
+	if cm.IsDead {
+		fmt.Fprintf(&b, " dead=%v", cm.IsDead)
+	}
+	if cm.Failures > 0 {
+		fmt.Fprintf(&b, " failures=%d", cm.Failures)
+	}
+	if cm.DeadSince != nil {
+		fmt.Fprintf(&b, " dead_since=%s", cm.DeadSince.Local().Format(time.Stamp))
+	}
+	b.WriteString("}")
+	return b.String()
+}
diff --git a/estransport/metrics_internal_test.go b/estransport/metrics_internal_test.go
new file mode 100644
index 0000000000..2de307d035
--- /dev/null
+++ b/estransport/metrics_internal_test.go
@@ -0,0 +1,112 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package estransport
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"regexp"
+	"testing"
+	"time"
+)
+
+func TestMetrics(t *testing.T) {
+	t.Run("Metrics()", func(t *testing.T) {
+		tp, _ := New(
+			Config{
+				URLs: []*url.URL{
+					{Scheme: "http", Host: "foo1"},
+					{Scheme: "http", Host: "foo2"},
+					{Scheme: "http", Host: "foo3"},
+				},
+				DisableRetry:  true,
+				EnableMetrics: true,
+			},
+		)
+
+		tp.metrics.requests = 3
+		tp.metrics.failures = 4
+		tp.metrics.responses[200] = 1
+		tp.metrics.responses[404] = 2
+
+		req, _ := http.NewRequest("HEAD", "/", nil)
+		tp.Perform(req)
+
+		m, err := tp.Metrics()
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		fmt.Println(m)
+
+		if m.Requests != 4 {
+			t.Errorf("Unexpected output, want=4, got=%d", m.Requests)
+		}
+		if m.Failures != 5 {
+			t.Errorf("Unexpected output, want=5, got=%d", m.Failures)
+		}
+		if len(m.Responses) != 2 {
+			t.Errorf("Unexpected output: %+v", m.Responses)
+		}
+		if len(m.Connections) != 3 {
+			t.Errorf("Unexpected output: %+v", m.Connections)
+		}
+	})
+
+	t.Run("Metrics() when not enabled", func(t *testing.T) {
+		tp, _ := New(Config{})
+
+		_, err := tp.Metrics()
+		if err == nil {
+			t.Fatalf("Expected error, got: %v", err)
+		}
+	})
+
+	t.Run("String()", func(t *testing.T) {
+		var m ConnectionMetric
+
+		m = ConnectionMetric{URL: "http://foo1"}
+
+		if m.String() != "{http://foo1}" {
+			t.Errorf("Unexpected output: %s", m)
+		}
+
+		tt, _ := time.Parse(time.RFC3339, "2010-11-11T11:00:00Z")
+		m = ConnectionMetric{
+			URL:       "http://foo2",
+			IsDead:    true,
+			Failures:  123,
+			DeadSince: &tt,
+		}
+
+		match, err := regexp.MatchString(
+			`{http://foo2 dead=true failures=123 dead_since=Nov 11 \d+:00:00}`,
+			m.String(),
+		)
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if !match {
+			t.Errorf("Unexpected output: %s", m)
+		}
+	})
+}
diff --git a/estransport/selector.go b/estransport/selector.go
deleted file mode 100755
index 45de0deb59..0000000000
--- a/estransport/selector.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package estransport
-
-import (
-	"container/ring"
-	"errors"
-	"net/url"
-	"sync"
-)
-
-// Selector defines the interface for selecting URLs for performing request.
-//
-type Selector interface {
-	Select() (*url.URL, error)
-}
-
-// RoundRobinSelector implements a round-robin selection strategy.
-//
-type RoundRobinSelector struct {
-	sync.Mutex
-	ring *ring.Ring
-}
-
-// Select returns a URL or error from the list of URLs in a round-robin fashion.
-//
-func (r *RoundRobinSelector) Select() (*url.URL, error) {
-	r.Lock()
-	defer r.Unlock()
-
-	if r.ring.Len() < 1 {
-		return nil, errors.New("No URL available")
-	}
-
-	v := r.ring.Value
-	if ov, ok := v.(*url.URL); !ok || ov == nil {
-		return nil, errors.New("No URL available")
-	}
-
-	r.ring = r.ring.Next()
-	return v.(*url.URL), nil
-}
-
-// NewRoundRobinSelector creates a new RoundRobinSelector.
-//
-func NewRoundRobinSelector(urls ...*url.URL) *RoundRobinSelector {
-	r := RoundRobinSelector{}
-
-	r.ring = ring.New(len(urls))
-	for _, u := range urls {
-		r.ring.Value = u
-		r.ring = r.ring.Next()
-	}
-
-	return &r
-}
diff --git a/estransport/testdata/cert.pem b/estransport/testdata/cert.pem
new file mode 100644
index 0000000000..75310cf935
--- /dev/null
+++ b/estransport/testdata/cert.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+jCCAeKgAwIBAgIRAPX2ep98yDY2s0ykr/Mv7DAwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xOTExMDIwOTIyNDZaFw0yMDExMDEwOTIy
+NDZaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDB0m5QrKyFALYrB2Dpac8RK1cU3edoiowIS00GRHm3dp7oeqmbXwJ4
+RFDDejM1NkVigkLSzCoDZQIUDiNQ1q7TdWQyWpiTv8d1MlT8kIq3wup4DyFPKEDZ
+C1X1fZeitOhj08E5X55voq5QAQLfCeSCWB4aP8+/e3KMgSk4GjKxfkAjoT6fSc38
+atdRZ1TTzwCJupiAZ54zYlL7gGDjw8K8Y7xRUYD+QiD7onghb0+jJbhShTUO3Rli
+nMfdeqICGN8LOqBfOuxAm1tl/+LFnqI8B/tJ8uo3YrOH2CXt1v8EauASEnIRXKTX
+Nrf+y1+PZlYwIkCDVQW8oYCqXzexY/q5AgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
+CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEADamo8m4XkgvX56TDQJiII8Zl
+S5d1GnCKxzqHXbDse7d5fOUl3FjO5ZaMbn0CiExv8tWbHlg7P9NCsBrqAxUTReKE
+cWTywC99wvQzEqfSJfW/Q8vTbbOw4uM9RgYDG+mfk66KC+M2MN81i/cHUKxq7N7v
+7Y6s16rtxqFzerGgAKLppg52RJNDhCDPumnSHp1rm4RjrLlG+qZpo3/37mXdNd5Z
+JvP/Uki4FrZw46TEbMw2f1hnXQtwgE5DoD6vDpNHG5ffVBpO6/OOfnQJtnmN3gsZ
+MmdgdEzroVPY6vs9WveNyIkIHip0QgHt7jk2vW3g1lOBw1cHuwZZkUeQ9yz3bQ==
+-----END CERTIFICATE-----
diff --git a/estransport/testdata/key.pem b/estransport/testdata/key.pem
new file mode 100644
index 0000000000..db3f890639
--- /dev/null
+++ b/estransport/testdata/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDB0m5QrKyFALYr
+B2Dpac8RK1cU3edoiowIS00GRHm3dp7oeqmbXwJ4RFDDejM1NkVigkLSzCoDZQIU
+DiNQ1q7TdWQyWpiTv8d1MlT8kIq3wup4DyFPKEDZC1X1fZeitOhj08E5X55voq5Q
+AQLfCeSCWB4aP8+/e3KMgSk4GjKxfkAjoT6fSc38atdRZ1TTzwCJupiAZ54zYlL7
+gGDjw8K8Y7xRUYD+QiD7onghb0+jJbhShTUO3RlinMfdeqICGN8LOqBfOuxAm1tl
+/+LFnqI8B/tJ8uo3YrOH2CXt1v8EauASEnIRXKTXNrf+y1+PZlYwIkCDVQW8oYCq
+XzexY/q5AgMBAAECggEAJUIEPrHSwAZw/jh+4p+aVFyWcsZtU2U+oeGHvuqu0xuU
+VHAv5lQPL3tCYzE8YsA5+kO8ALWKZfimu6A0HbgHB1MLnbpYlh5JgzfXqm1GnSh0
+1ftilcrRHGfXcEdiPL615WqxPAwrcp49D9gB60oFiSDTOIyHrPFYBbZWbBhtIj0i
+plEOSNlqch64oRuj/jWsUOSJk3MLm00lim81yfCG8vjQxsQ1MsdJh2E0GH58t4W6
+UUvHp85iZHrPLtWt9iI9hng9b51RBKKqqyjhfEW+jNgUdOlWBNkaCTzyCjRAu9fM
+7VFhzCII6APVH4NhIbotx+NoA9sTSOdRFvcpPNJMGQKBgQD0vf8P/pQfOv176Bju
+fWno9ZL+bwCe1YW6FaHIMJ5vz6GR+kmDMxnjEJi9eCR9mZ8Ag4NotItTZ1lAeLdO
+MkfNXMolI3GTfSZ1qVoYuExOU3BMER2XgHCCo/jPWWL50YVUAUiIJd26KPn+CnrW
+EUQbtGMtnl0pg7chooeifgBHGwKBgQDKvNC0TJaQz/P8mTeJdGUfP5px37nYBM0Y
+hTWGGnMiU/OhjLLOysgUANj4XG12gzz1CMwND/HldgRWoZXqMEuRr/KoWTIREra1
+vjN+HEsTrujcB3+2peUBVTOFaoFfTH1ohbUp+wYw05y9Iz7DgY/EVmnZzusdxvxL
+UFda696+uwKBgGPkTH+9u71HeYCiSdLFk33HBdkde1ZY9jzuaVrpJTGjwGFxk6Ge
+MNmxw3XJ3LL7CZ/PDcqlrhw7mX0sCD09XnsefU9NOSUmtpTdq21dg5+QhMw3TCmy
+/bkEriALbs9iShXwdCdFtUsvQGIE6wAGihL4vGY5NfMk1JFA4jVbUkezAoGARcIO
+Nducextyolm96Efqe4QRClmmwpN0VpmPPyNetlMYo1+cLtdLXMal4V88MukZUl7C
+h0QTQZcICx7yTHBtsCVQY2i9d25u+74ETcJCevVWHk9ePGR8labRYXiyJy5UgGBx
+Y46CJM7LQbEc6XxtEWuCZHV0JPzQ1sFALYK3U/0CgYEAps8bjTS0BR5yb/NSO+YR
+Wd9/9Jh1fUgf/lWQUPBBdThOqWXtNYTHwTUdqmr6td+urlz6F2PpD7FGNBlNc8Ia
+352T6k2fGNzce9bWdaxagbC4zDQeBWZtO8nLFQYUqkxf/UQSEjzHglZ0ZtpiRJ2M
+TrUFwQLe98VOuKjkOsqXn5A=
+-----END PRIVATE KEY-----
diff --git a/estransport/testdata/nodes.info.json b/estransport/testdata/nodes.info.json
new file mode 100644
index 0000000000..d5c9175e9c
--- /dev/null
+++ b/estransport/testdata/nodes.info.json
@@ -0,0 +1,83 @@
+{
+  "_nodes": {
+    "total": 3,
+    "successful": 3,
+    "failed": 0
+  },
+  "cluster_name": "elasticsearch",
+  "nodes": {
+    "8g1UNpQNS06tlH1DUMBNhg": {
+      "name": "es1",
+      "transport_address": "127.0.0.1:9300",
+      "host": "127.0.0.1",
+      "ip": "127.0.0.1",
+      "version": "7.4.2",
+      "build_flavor": "default",
+      "build_type": "tar",
+      "build_hash": "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
+      "roles": ["ingest", "master", "data", "ml"],
+      "attributes": {
+        "ml.machine_memory": "8589934592",
+        "xpack.installed": "true",
+        "ml.max_open_jobs": "20"
+      },
+      "http": {
+        "bound_address": [
+          "[::1]:10001",
+          "127.0.0.1:10001"
+        ],
+        "publish_address": "127.0.0.1:10001",
+        "max_content_length_in_bytes": 104857600
+      }
+    },
+    "8YR2EBk_QvWI4guQK292RA": {
+      "name": "es2",
+      "transport_address": "127.0.0.1:9302",
+      "host": "127.0.0.1",
+      "ip": "127.0.0.1",
+      "version": "7.4.2",
+      "build_flavor": "default",
+      "build_type": "tar",
+      "build_hash": "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
+      "roles": ["ingest", "master", "data", "ml"],
+      "attributes": {
+        "ml.machine_memory": "8589934592",
+        "ml.max_open_jobs": "20",
+        "xpack.installed": "true"
+      },
+      "http": {
+        "bound_address": [
+          "127.0.0.1:10002",
+          "[::1]:10002",
+          "[fe80::1]:10002"
+        ],
+        "publish_address": "localhost/127.0.0.1:10002",
+        "max_content_length_in_bytes": 104857600
+      }
+    },
+    "oSVIMafYQD-4kD0Lz6H4-g": {
+      "name": "es3",
+      "transport_address": "127.0.0.1:9301",
+      "host": "127.0.0.1",
+      "ip": "127.0.0.1",
+      "version": "7.4.2",
+      "build_flavor": "default",
+      "build_type": "tar",
+      "build_hash": "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
+      "roles": ["master"],
+      "attributes": {
+        "ml.machine_memory": "8589934592",
+        "ml.max_open_jobs": "20",
+        "xpack.installed": "true"
+      },
+      "http": {
+        "bound_address": [
+          "[::1]:10003",
+          "127.0.0.1:10003"
+        ],
+        "publish_address": "127.0.0.1:10003",
+        "max_content_length_in_bytes": 104857600
+      }
+    }
+  }
+}
diff --git a/esutil/bulk_indexer.go b/esutil/bulk_indexer.go
new file mode 100644
index 0000000000..8959272297
--- /dev/null
+++ b/esutil/bulk_indexer.go
@@ -0,0 +1,619 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package esutil
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"runtime"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+// BulkIndexer represents a parallel, asynchronous, efficient indexer for Elasticsearch.
+//
+type BulkIndexer interface {
+	// Add adds an item to the indexer. It returns an error when the item cannot be added.
+	// Use the OnSuccess and OnFailure callbacks to get the operation result for the item.
+	//
+	// You must call the Close() method after you're done adding items.
+	//
+	// It is safe for concurrent use. When it's called from goroutines,
+	// they must finish before the call to Close, eg. using sync.WaitGroup.
+	Add(context.Context, BulkIndexerItem) error
+
+	// Close waits until all added items are flushed and closes the indexer.
+	Close(context.Context) error
+
+	// Stats returns indexer statistics.
+	Stats() BulkIndexerStats
+}
+
+// BulkIndexerConfig represents configuration of the indexer.
+//
+type BulkIndexerConfig struct {
+	NumWorkers    int           // The number of workers. Defaults to runtime.NumCPU().
+	FlushBytes    int           // The flush threshold in bytes. Defaults to 5MB.
+	FlushInterval time.Duration // The flush threshold as duration. Defaults to 30sec.
+
+	Client      *elasticsearch.Client   // The Elasticsearch client.
+	Decoder     BulkResponseJSONDecoder // A custom JSON decoder.
+	DebugLogger BulkIndexerDebugLogger  // An optional logger for debugging.
+
+	OnError      func(context.Context, error)          // Called for indexer errors.
+	OnFlushStart func(context.Context) context.Context // Called when the flush starts.
+	OnFlushEnd   func(context.Context)                 // Called when the flush ends.
+
+	// Parameters of the Bulk API.
+	Index               string
+	ErrorTrace          bool
+	FilterPath          []string
+	Header              http.Header
+	Human               bool
+	Pipeline            string
+	Pretty              bool
+	Refresh             string
+	Routing             string
+	Source              []string
+	SourceExcludes      []string
+	SourceIncludes      []string
+	Timeout             time.Duration
+	WaitForActiveShards string
+}
+
+// BulkIndexerStats represents the indexer statistics.
+//
+type BulkIndexerStats struct {
+	NumAdded    uint64
+	NumFlushed  uint64
+	NumFailed   uint64
+	NumIndexed  uint64
+	NumCreated  uint64
+	NumUpdated  uint64
+	NumDeleted  uint64
+	NumRequests uint64
+}
+
+// BulkIndexerItem represents an indexer item.
+//
+type BulkIndexerItem struct {
+	Index           string
+	Action          string
+	DocumentID      string
+	Routing         string
+	Version         *int64
+	VersionType     string
+	Body            io.Reader
+	RetryOnConflict *int
+
+	OnSuccess func(context.Context, BulkIndexerItem, BulkIndexerResponseItem)        // Per item
+	OnFailure func(context.Context, BulkIndexerItem, BulkIndexerResponseItem, error) // Per item
+}
+
+// BulkIndexerResponse represents the Elasticsearch response.
+//
+type BulkIndexerResponse struct {
+	Took      int                                  `json:"took"`
+	HasErrors bool                                 `json:"errors"`
+	Items     []map[string]BulkIndexerResponseItem `json:"items,omitempty"`
+}
+
+// BulkIndexerResponseItem represents the Elasticsearch response item.
+//
+type BulkIndexerResponseItem struct {
+	Index      string `json:"_index"`
+	DocumentID string `json:"_id"`
+	Version    int64  `json:"_version"`
+	Result     string `json:"result"`
+	Status     int    `json:"status"`
+	SeqNo      int64  `json:"_seq_no"`
+	PrimTerm   int64  `json:"_primary_term"`
+
+	Shards struct {
+		Total      int `json:"total"`
+		Successful int `json:"successful"`
+		Failed     int `json:"failed"`
+	} `json:"_shards"`
+
+	Error struct {
+		Type   string `json:"type"`
+		Reason string `json:"reason"`
+		Cause  struct {
+			Type   string `json:"type"`
+			Reason string `json:"reason"`
+		} `json:"caused_by"`
+	} `json:"error,omitempty"`
+}
+
+// BulkResponseJSONDecoder defines the interface for custom JSON decoders.
+//
+type BulkResponseJSONDecoder interface {
+	UnmarshalFromReader(io.Reader, *BulkIndexerResponse) error
+}
+
+// BulkIndexerDebugLogger defines the interface for a debugging logger.
+//
+type BulkIndexerDebugLogger interface {
+	Printf(string, ...interface{})
+}
+
+type bulkIndexer struct {
+	wg      sync.WaitGroup
+	queue   chan BulkIndexerItem
+	workers []*worker
+	ticker  *time.Ticker
+	done    chan bool
+	stats   *bulkIndexerStats
+
+	config BulkIndexerConfig
+}
+
+type bulkIndexerStats struct {
+	numAdded    uint64
+	numFlushed  uint64
+	numFailed   uint64
+	numIndexed  uint64
+	numCreated  uint64
+	numUpdated  uint64
+	numDeleted  uint64
+	numRequests uint64
+}
+
+// NewBulkIndexer creates a new bulk indexer.
+//
+func NewBulkIndexer(cfg BulkIndexerConfig) (BulkIndexer, error) {
+	if cfg.Client == nil {
+		cfg.Client, _ = elasticsearch.NewDefaultClient()
+	}
+
+	if cfg.Decoder == nil {
+		cfg.Decoder = defaultJSONDecoder{}
+	}
+
+	if cfg.NumWorkers == 0 {
+		cfg.NumWorkers = runtime.NumCPU()
+	}
+
+	if cfg.FlushBytes == 0 {
+		cfg.FlushBytes = 5e+6
+	}
+
+	if cfg.FlushInterval == 0 {
+		cfg.FlushInterval = 30 * time.Second
+	}
+
+	bi := bulkIndexer{
+		config: cfg,
+		done:   make(chan bool),
+		stats:  &bulkIndexerStats{},
+	}
+
+	bi.init()
+
+	return &bi, nil
+}
+
+// Add adds an item to the indexer.
+//
+// Adding an item after a call to Close() will panic.
+//
+func (bi *bulkIndexer) Add(ctx context.Context, item BulkIndexerItem) error {
+	atomic.AddUint64(&bi.stats.numAdded, 1)
+
+	select {
+	case <-ctx.Done():
+		if bi.config.OnError != nil {
+			bi.config.OnError(ctx, ctx.Err())
+		}
+		return ctx.Err()
+	case bi.queue <- item:
+	}
+
+	return nil
+}
+
+// Close stops the periodic flush, closes the indexer queue channel,
+// notifies the done channel and calls flush on all writers.
+//
+func (bi *bulkIndexer) Close(ctx context.Context) error {
+	bi.ticker.Stop()
+	close(bi.queue)
+	bi.done <- true
+
+	select {
+	case <-ctx.Done():
+		if bi.config.OnError != nil {
+			bi.config.OnError(ctx, ctx.Err())
+		}
+		return ctx.Err()
+	default:
+		bi.wg.Wait()
+	}
+
+	for _, w := range bi.workers {
+		w.mu.Lock()
+		if w.buf.Len() > 0 {
+			if err := w.flush(ctx); err != nil {
+				w.mu.Unlock()
+				if bi.config.OnError != nil {
+					bi.config.OnError(ctx, err)
+				}
+				continue
+			}
+		}
+		w.mu.Unlock()
+	}
+	return nil
+}
+
+// Stats returns indexer statistics.
+//
+func (bi *bulkIndexer) Stats() BulkIndexerStats {
+	return BulkIndexerStats{
+		NumAdded:    atomic.LoadUint64(&bi.stats.numAdded),
+		NumFlushed:  atomic.LoadUint64(&bi.stats.numFlushed),
+		NumFailed:   atomic.LoadUint64(&bi.stats.numFailed),
+		NumIndexed:  atomic.LoadUint64(&bi.stats.numIndexed),
+		NumCreated:  atomic.LoadUint64(&bi.stats.numCreated),
+		NumUpdated:  atomic.LoadUint64(&bi.stats.numUpdated),
+		NumDeleted:  atomic.LoadUint64(&bi.stats.numDeleted),
+		NumRequests: atomic.LoadUint64(&bi.stats.numRequests),
+	}
+}
+
+// init initializes the bulk indexer.
+//
+func (bi *bulkIndexer) init() {
+	bi.queue = make(chan BulkIndexerItem, bi.config.NumWorkers)
+
+	for i := 1; i <= bi.config.NumWorkers; i++ {
+		w := worker{
+			id:  i,
+			ch:  bi.queue,
+			bi:  bi,
+			buf: bytes.NewBuffer(make([]byte, 0, bi.config.FlushBytes)),
+			aux: make([]byte, 0, 512)}
+		w.run()
+		bi.workers = append(bi.workers, &w)
+	}
+	bi.wg.Add(bi.config.NumWorkers)
+
+	bi.ticker = time.NewTicker(bi.config.FlushInterval)
+	go func() {
+		ctx := context.Background()
+		for {
+			select {
+			case <-bi.done:
+				return
+			case <-bi.ticker.C:
+				if bi.config.DebugLogger != nil {
+					bi.config.DebugLogger.Printf("[indexer] Auto-flushing workers after %s\n", bi.config.FlushInterval)
+				}
+				for _, w := range bi.workers {
+					w.mu.Lock()
+					if w.buf.Len() > 0 {
+						if err := w.flush(ctx); err != nil {
+							w.mu.Unlock()
+							if bi.config.OnError != nil {
+								bi.config.OnError(ctx, err)
+							}
+							continue
+						}
+					}
+					w.mu.Unlock()
+				}
+			}
+		}
+	}()
+}
+
+// worker represents an indexer worker.
+//
+type worker struct {
+	id    int
+	ch    <-chan BulkIndexerItem
+	mu    sync.Mutex
+	bi    *bulkIndexer
+	buf   *bytes.Buffer
+	aux   []byte
+	items []BulkIndexerItem
+}
+
+// run launches the worker in a goroutine.
+//
+func (w *worker) run() {
+	go func() {
+		ctx := context.Background()
+
+		if w.bi.config.DebugLogger != nil {
+			w.bi.config.DebugLogger.Printf("[worker-%03d] Started\n", w.id)
+		}
+		defer w.bi.wg.Done()
+
+		for item := range w.ch {
+			w.mu.Lock()
+
+			if w.bi.config.DebugLogger != nil {
+				w.bi.config.DebugLogger.Printf("[worker-%03d] Received item [%s:%s]\n", w.id, item.Action, item.DocumentID)
+			}
+
+			if err := w.writeMeta(item); err != nil {
+				if item.OnFailure != nil {
+					item.OnFailure(ctx, item, BulkIndexerResponseItem{}, err)
+				}
+				atomic.AddUint64(&w.bi.stats.numFailed, 1)
+				w.mu.Unlock()
+				continue
+			}
+
+			if err := w.writeBody(&item); err != nil {
+				if item.OnFailure != nil {
+					item.OnFailure(ctx, item, BulkIndexerResponseItem{}, err)
+				}
+				atomic.AddUint64(&w.bi.stats.numFailed, 1)
+				w.mu.Unlock()
+				continue
+			}
+
+			w.items = append(w.items, item)
+			if w.buf.Len() >= w.bi.config.FlushBytes {
+				if err := w.flush(ctx); err != nil {
+					w.mu.Unlock()
+					if w.bi.config.OnError != nil {
+						w.bi.config.OnError(ctx, err)
+					}
+					continue
+				}
+			}
+			w.mu.Unlock()
+		}
+	}()
+}
+
+// writeMeta formats and writes the item metadata to the buffer; it must be called under a lock.
+//
+func (w *worker) writeMeta(item BulkIndexerItem) error {
+	w.buf.WriteRune('{')
+	w.aux = strconv.AppendQuote(w.aux, item.Action)
+	w.buf.Write(w.aux)
+	w.aux = w.aux[:0]
+	w.buf.WriteRune(':')
+	w.buf.WriteRune('{')
+	if item.DocumentID != "" {
+		w.buf.WriteString(`"_id":`)
+		w.aux = strconv.AppendQuote(w.aux, item.DocumentID)
+		w.buf.Write(w.aux)
+		w.aux = w.aux[:0]
+	}
+
+	if item.DocumentID != "" && item.Version != nil {
+		w.buf.WriteRune(',')
+		w.buf.WriteString(`"version":`)
+		w.buf.WriteString(strconv.FormatInt(*item.Version, 10))
+	}
+
+	if item.DocumentID != "" && item.VersionType != "" {
+		w.buf.WriteRune(',')
+		w.buf.WriteString(`"version_type":`)
+		w.aux = strconv.AppendQuote(w.aux, item.VersionType)
+		w.buf.Write(w.aux)
+		w.aux = w.aux[:0]
+	}
+
+	if item.Routing != "" {
+		if item.DocumentID != "" {
+			w.buf.WriteRune(',')
+		}
+		w.buf.WriteString(`"_routing":`)
+		w.aux = strconv.AppendQuote(w.aux, item.Routing)
+		w.buf.Write(w.aux)
+		w.aux = w.aux[:0]
+	}
+	if item.Index != "" {
+		if item.DocumentID != "" || item.Routing != "" {
+			w.buf.WriteRune(',')
+		}
+		w.buf.WriteString(`"_index":`)
+		w.aux = strconv.AppendQuote(w.aux, item.Index)
+		w.buf.Write(w.aux)
+		w.aux = w.aux[:0]
+	}
+	w.buf.WriteRune('}')
+	w.buf.WriteRune('}')
+	w.buf.WriteRune('\n')
+	return nil
+}
+
+// writeBody writes the item body to the buffer; it must be called under a lock.
+//
+func (w *worker) writeBody(item *BulkIndexerItem) error {
+	if item.Body != nil {
+
+		var getBody func() io.Reader
+
+		if item.OnSuccess != nil || item.OnFailure != nil {
+			var buf bytes.Buffer
+			buf.ReadFrom(item.Body)
+			getBody = func() io.Reader {
+				r := buf
+				return ioutil.NopCloser(&r)
+			}
+			item.Body = getBody()
+		}
+
+		if _, err := w.buf.ReadFrom(item.Body); err != nil {
+			if w.bi.config.OnError != nil {
+				w.bi.config.OnError(context.Background(), err)
+			}
+			return err
+		}
+		w.buf.WriteRune('\n')
+
+		if getBody != nil && (item.OnSuccess != nil || item.OnFailure != nil) {
+			item.Body = getBody()
+		}
+	}
+	return nil
+}
+
+// flush writes out the worker buffer; it must be called under a lock.
+//
+func (w *worker) flush(ctx context.Context) error {
+	if w.bi.config.OnFlushStart != nil {
+		ctx = w.bi.config.OnFlushStart(ctx)
+	}
+
+	if w.bi.config.OnFlushEnd != nil {
+		defer func() { w.bi.config.OnFlushEnd(ctx) }()
+	}
+
+	if w.buf.Len() < 1 {
+		if w.bi.config.DebugLogger != nil {
+			w.bi.config.DebugLogger.Printf("[worker-%03d] Flush: Buffer empty\n", w.id)
+		}
+		return nil
+	}
+
+	var (
+		err error
+		blk BulkIndexerResponse
+	)
+
+	defer func() {
+		w.items = w.items[:0]
+		w.buf.Reset()
+	}()
+
+	if w.bi.config.DebugLogger != nil {
+		w.bi.config.DebugLogger.Printf("[worker-%03d] Flush: %s\n", w.id, w.buf.String())
+	}
+
+	atomic.AddUint64(&w.bi.stats.numRequests, 1)
+	req := esapi.BulkRequest{
+		Index: w.bi.config.Index,
+		Body:  w.buf,
+
+		Pipeline:            w.bi.config.Pipeline,
+		Refresh:             w.bi.config.Refresh,
+		Routing:             w.bi.config.Routing,
+		Source:              w.bi.config.Source,
+		SourceExcludes:      w.bi.config.SourceExcludes,
+		SourceIncludes:      w.bi.config.SourceIncludes,
+		Timeout:             w.bi.config.Timeout,
+		WaitForActiveShards: w.bi.config.WaitForActiveShards,
+
+		Pretty:     w.bi.config.Pretty,
+		Human:      w.bi.config.Human,
+		ErrorTrace: w.bi.config.ErrorTrace,
+		FilterPath: w.bi.config.FilterPath,
+		Header:     w.bi.config.Header,
+	}
+
+	// Add Header and MetaHeader to config if not already set
+	if req.Header == nil {
+		req.Header = http.Header{}
+	}
+	req.Header.Set(estransport.HeaderClientMeta, "h=bp")
+
+	res, err := req.Do(ctx, w.bi.config.Client)
+	if err != nil {
+		atomic.AddUint64(&w.bi.stats.numFailed, uint64(len(w.items)))
+		if w.bi.config.OnError != nil {
+			w.bi.config.OnError(ctx, fmt.Errorf("flush: %s", err))
+		}
+		return fmt.Errorf("flush: %s", err)
+	}
+	if res.Body != nil {
+		defer res.Body.Close()
+	}
+	if res.IsError() {
+		atomic.AddUint64(&w.bi.stats.numFailed, uint64(len(w.items)))
+		// TODO(karmi): Wrap error (include response struct)
+		if w.bi.config.OnError != nil {
+			w.bi.config.OnError(ctx, fmt.Errorf("flush: %s", err))
+		}
+		return fmt.Errorf("flush: %s", res.String())
+	}
+
+	if err := w.bi.config.Decoder.UnmarshalFromReader(res.Body, &blk); err != nil {
+		// TODO(karmi): Wrap error (include response struct)
+		if w.bi.config.OnError != nil {
+			w.bi.config.OnError(ctx, fmt.Errorf("flush: %s", err))
+		}
+		return fmt.Errorf("flush: error parsing response body: %s", err)
+	}
+
+	for i, blkItem := range blk.Items {
+		var (
+			item BulkIndexerItem
+			info BulkIndexerResponseItem
+			op   string
+		)
+
+		item = w.items[i]
+		// The Elasticsearch bulk response contains an array of maps like this:
+		//   [ { "index": { ... } }, { "create": { ... } }, ... ]
+		// We range over the map, to set the first key and value as "op" and "info".
+		for k, v := range blkItem {
+			op = k
+			info = v
+		}
+		if info.Error.Type != "" || info.Status > 201 {
+			atomic.AddUint64(&w.bi.stats.numFailed, 1)
+			if item.OnFailure != nil {
+				item.OnFailure(ctx, item, info, nil)
+			}
+		} else {
+			atomic.AddUint64(&w.bi.stats.numFlushed, 1)
+
+			switch op {
+			case "index":
+				atomic.AddUint64(&w.bi.stats.numIndexed, 1)
+			case "create":
+				atomic.AddUint64(&w.bi.stats.numCreated, 1)
+			case "delete":
+				atomic.AddUint64(&w.bi.stats.numDeleted, 1)
+			case "update":
+				atomic.AddUint64(&w.bi.stats.numUpdated, 1)
+			}
+
+			if item.OnSuccess != nil {
+				item.OnSuccess(ctx, item, info)
+			}
+		}
+	}
+
+	return err
+}
+
+type defaultJSONDecoder struct{}
+
+func (d defaultJSONDecoder) UnmarshalFromReader(r io.Reader, blk *BulkIndexerResponse) error {
+	return json.NewDecoder(r).Decode(blk)
+}
diff --git a/esutil/bulk_indexer_benchmark_test.go b/esutil/bulk_indexer_benchmark_test.go
new file mode 100644
index 0000000000..d96b2ca863
--- /dev/null
+++ b/esutil/bulk_indexer_benchmark_test.go
@@ -0,0 +1,89 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package esutil_test
+
+import (
+	"bytes"
+	"context"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+var mockResponseBody = `{
+  "took": 30,
+  "errors": false,
+  "items": [
+    {
+      "index": {
+        "_index": "test",
+        "_id": "1",
+        "_version": 1,
+        "result": "created",
+        "_shards": { "total": 2, "successful": 1, "failed": 0 },
+        "status": 201,
+        "_seq_no": 0,
+        "_primary_term": 1
+      }
+    }
+  ]
+}`
+
+type mockTransp struct{}
+
+func (t *mockTransp) RoundTrip(req *http.Request) (*http.Response, error) {
+	return &http.Response{Body: ioutil.NopCloser(strings.NewReader(mockResponseBody))}, nil // 1x alloc
+}
+
+func BenchmarkBulkIndexer(b *testing.B) {
+	b.ReportAllocs()
+
+	b.Run("Basic", func(b *testing.B) {
+		b.ResetTimer()
+
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransp{}})
+		bi, _ := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+			Client:     es,
+			FlushBytes: 1024,
+		})
+		defer bi.Close(context.Background())
+
+		docID := make([]byte, 0, 16)
+		var docIDBuf bytes.Buffer
+		docIDBuf.Grow(cap(docID))
+
+		for i := 0; i < b.N; i++ {
+			docID = strconv.AppendInt(docID, int64(i), 10)
+			docIDBuf.Write(docID)
+			bi.Add(context.Background(), esutil.BulkIndexerItem{
+				Action:     "index",
+				DocumentID: docIDBuf.String(),                  // 1x alloc
+				Body:       strings.NewReader(`{"foo":"bar"}`), // 1x alloc
+			})
+			docID = docID[:0]
+			docIDBuf.Reset()
+		}
+	})
+}
diff --git a/esutil/bulk_indexer_example_test.go b/esutil/bulk_indexer_example_test.go
new file mode 100644
index 0000000000..9f3ff0e1ea
--- /dev/null
+++ b/esutil/bulk_indexer_example_test.go
@@ -0,0 +1,128 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package esutil_test
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"strings"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+func ExampleNewBulkIndexer() {
+	log.SetFlags(0)
+
+	// Create the Elasticsearch client
+	//
+	es, err := elasticsearch.NewClient(elasticsearch.Config{
+		// Retry on 429 TooManyRequests statuses
+		//
+		RetryOnStatus: []int{502, 503, 504, 429},
+
+		// A simple incremental backoff function
+		//
+		RetryBackoff: func(i int) time.Duration { return time.Duration(i) * 100 * time.Millisecond },
+
+		// Retry up to 5 attempts
+		//
+		MaxRetries: 5,
+	})
+	if err != nil {
+		log.Fatalf("Error creating the client: %s", err)
+	}
+
+	// Create the indexer
+	//
+	indexer, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+		Client:     es,     // The Elasticsearch client
+		Index:      "test", // The default index name
+		NumWorkers: 4,      // The number of worker goroutines (default: number of CPUs)
+		FlushBytes: 5e+6,   // The flush threshold in bytes (default: 5M)
+	})
+	if err != nil {
+		log.Fatalf("Error creating the indexer: %s", err)
+	}
+
+	// Add an item to the indexer
+	//
+	err = indexer.Add(
+		context.Background(),
+		esutil.BulkIndexerItem{
+			// Action field configures the operation to perform (index, create, delete, update)
+			Action: "index",
+
+			// DocumentID is the optional document ID
+			DocumentID: "1",
+
+			// Body is an `io.Reader` with the payload
+			Body: strings.NewReader(`{"title":"Test"}`),
+
+			// OnSuccess is the optional callback for each successful operation
+			OnSuccess: func(
+				ctx context.Context,
+				item esutil.BulkIndexerItem,
+				res esutil.BulkIndexerResponseItem,
+			) {
+				fmt.Printf("[%d] %s test/%s", res.Status, res.Result, item.DocumentID)
+			},
+
+			// OnFailure is the optional callback for each failed operation
+			OnFailure: func(
+				ctx context.Context,
+				item esutil.BulkIndexerItem,
+				res esutil.BulkIndexerResponseItem, err error,
+			) {
+				if err != nil {
+					log.Printf("ERROR: %s", err)
+				} else {
+					log.Printf("ERROR: %s: %s", res.Error.Type, res.Error.Reason)
+				}
+			},
+		},
+	)
+	if err != nil {
+		log.Fatalf("Unexpected error: %s", err)
+	}
+
+	// Close the indexer channel and flush remaining items
+	//
+	if err := indexer.Close(context.Background()); err != nil {
+		log.Fatalf("Unexpected error: %s", err)
+	}
+
+	// Report the indexer statistics
+	//
+	stats := indexer.Stats()
+	if stats.NumFailed > 0 {
+		log.Fatalf("Indexed [%d] documents with [%d] errors", stats.NumFlushed, stats.NumFailed)
+	} else {
+		log.Printf("Successfully indexed [%d] documents", stats.NumFlushed)
+	}
+
+	// For optimal performance, consider using a third-party package for JSON decoding and HTTP transport.
+	//
+	// For more information, examples and benchmarks, see:
+	//
+	// --> https://github.com/elastic/go-elasticsearch/tree/master/_examples/bulk
+}
diff --git a/esutil/bulk_indexer_integration_test.go b/esutil/bulk_indexer_integration_test.go
new file mode 100644
index 0000000000..8b6219dcd8
--- /dev/null
+++ b/esutil/bulk_indexer_integration_test.go
@@ -0,0 +1,252 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//go:build integration
+// +build integration
+
+package esutil_test
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+func TestBulkIndexerIntegration(t *testing.T) {
+	body := `{"body":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."}`
+
+	testCases := []struct {
+		name                       string
+		CompressRequestBodyEnabled bool
+	}{
+		{
+			name:                       "Without body compression",
+			CompressRequestBodyEnabled: false,
+		},
+		{
+			name:                       "With body compression",
+			CompressRequestBodyEnabled: true,
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Run("Default", func(t *testing.T) {
+				var countSuccessful uint64
+				indexName := "test-bulk-integration"
+
+				es, _ := elasticsearch.NewClient(elasticsearch.Config{
+					CompressRequestBody: tt.CompressRequestBodyEnabled,
+					Logger:              &estransport.ColorLogger{Output: os.Stdout},
+				})
+
+				es.Indices.Delete([]string{indexName}, es.Indices.Delete.WithIgnoreUnavailable(true))
+				es.Indices.Create(
+					indexName,
+					es.Indices.Create.WithBody(strings.NewReader(`{"settings": {"number_of_shards": 1, "number_of_replicas": 0, "refresh_interval":"5s"}}`)),
+					es.Indices.Create.WithWaitForActiveShards("1"))
+
+				bi, _ := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+					Index:  indexName,
+					Client: es,
+					// FlushBytes: 3e+6,
+				})
+
+				numItems := 100000
+				start := time.Now().UTC()
+
+				for i := 1; i <= numItems; i++ {
+					err := bi.Add(context.Background(), esutil.BulkIndexerItem{
+						Action:     "index",
+						DocumentID: strconv.Itoa(i),
+						Body:       strings.NewReader(body),
+						OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
+							atomic.AddUint64(&countSuccessful, 1)
+						},
+					})
+					if err != nil {
+						t.Fatalf("Unexpected error: %s", err)
+					}
+				}
+
+				if err := bi.Close(context.Background()); err != nil {
+					t.Errorf("Unexpected error: %s", err)
+				}
+
+				stats := bi.Stats()
+
+				if stats.NumAdded != uint64(numItems) {
+					t.Errorf("Unexpected NumAdded: want=%d, got=%d", numItems, stats.NumAdded)
+				}
+
+				if stats.NumIndexed != uint64(numItems) {
+					t.Errorf("Unexpected NumIndexed: want=%d, got=%d", numItems, stats.NumIndexed)
+				}
+
+				if stats.NumFailed != 0 {
+					t.Errorf("Unexpected NumFailed: want=0, got=%d", stats.NumFailed)
+				}
+
+				if countSuccessful != uint64(numItems) {
+					t.Errorf("Unexpected countSuccessful: want=%d, got=%d", numItems, countSuccessful)
+				}
+
+				fmt.Printf("  Added %d documents to indexer. Succeeded: %d. Failed: %d. Requests: %d. Duration: %s (%.0f docs/sec)\n",
+					stats.NumAdded,
+					stats.NumFlushed,
+					stats.NumFailed,
+					stats.NumRequests,
+					time.Since(start).Truncate(time.Millisecond),
+					1000.0/float64(time.Since(start)/time.Millisecond)*float64(stats.NumFlushed))
+			})
+
+			t.Run("Multiple indices", func(t *testing.T) {
+				es, _ := elasticsearch.NewClient(elasticsearch.Config{
+					CompressRequestBody: tt.CompressRequestBodyEnabled,
+					Logger:              &estransport.ColorLogger{Output: os.Stdout},
+				})
+
+				bi, _ := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+					Index:  "test-index-a",
+					Client: es,
+				})
+
+				// Default index
+				for i := 1; i <= 10; i++ {
+					err := bi.Add(context.Background(), esutil.BulkIndexerItem{
+						Action:     "index",
+						DocumentID: strconv.Itoa(i),
+						Body:       strings.NewReader(body),
+					})
+					if err != nil {
+						t.Fatalf("Unexpected error: %s", err)
+					}
+				}
+
+				// Index 1
+				for i := 1; i <= 10; i++ {
+					err := bi.Add(context.Background(), esutil.BulkIndexerItem{
+						Action: "index",
+						Index:  "test-index-b",
+						Body:   strings.NewReader(body),
+					})
+					if err != nil {
+						t.Fatalf("Unexpected error: %s", err)
+					}
+				}
+
+				// Index 2
+				for i := 1; i <= 10; i++ {
+					err := bi.Add(context.Background(), esutil.BulkIndexerItem{
+						Action: "index",
+						Index:  "test-index-c",
+						Body:   strings.NewReader(body),
+					})
+					if err != nil {
+						t.Fatalf("Unexpected error: %s", err)
+					}
+				}
+
+				if err := bi.Close(context.Background()); err != nil {
+					t.Errorf("Unexpected error: %s", err)
+				}
+				stats := bi.Stats()
+
+				expectedIndexed := 10 + 10 + 10
+				if stats.NumIndexed != uint64(expectedIndexed) {
+					t.Errorf("Unexpected NumIndexed: want=%d, got=%d", expectedIndexed, stats.NumIndexed)
+				}
+
+				res, err := es.Indices.Exists([]string{"test-index-a", "test-index-b", "test-index-c"})
+				if err != nil {
+					t.Fatalf("Unexpected error: %s", err)
+				}
+				if res.StatusCode != 200 {
+					t.Errorf("Expected indices to exist, but got a [%s] response", res.Status())
+				}
+			})
+
+			t.Run("External version", func(t *testing.T) {
+				var index string = "test-index-a"
+
+				es, _ := elasticsearch.NewClient(elasticsearch.Config{
+					CompressRequestBody: tt.CompressRequestBodyEnabled,
+					Logger:              &estransport.ColorLogger{Output: os.Stdout},
+				})
+
+				es.Indices.Delete([]string{index}, es.Indices.Delete.WithIgnoreUnavailable(true))
+				es.Indices.Create(index, es.Indices.Create.WithWaitForActiveShards("1"))
+
+				bulkIndex := func(bulkIndexer esutil.BulkIndexer, baseVersion int) {
+					var countTotal int = 500
+					var countSuccessful uint64
+					for i := 0; i < countTotal; i++ {
+						version := int64(baseVersion + i)
+						item := esutil.BulkIndexerItem{
+							Action:      "index",
+							Index:       index,
+							DocumentID:  strconv.Itoa(i),
+							Body:        strings.NewReader(body),
+							Version:     &version,
+							VersionType: "external",
+							OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, item2 esutil.BulkIndexerResponseItem) {
+								if version != item2.Version &&
+									version != *item.Version &&
+									item2.Result != "created" {
+									t.Fatalf("version mismatch, expected: %d, got: %d && %d", version, item.Version, item2.Version)
+								}
+								atomic.AddUint64(&countSuccessful, 1)
+							},
+						}
+						err := bulkIndexer.Add(context.Background(), item)
+						if err != nil {
+							t.Fatal(err)
+						}
+					}
+					if err := bulkIndexer.Close(context.Background()); err != nil {
+						t.Fatal(err)
+					}
+
+					if int(countSuccessful) != countTotal {
+						t.Fatalf("Unexpected countSuccessful, expected %d, got: %d", countTotal, countSuccessful)
+					}
+				}
+
+				bi, _ := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+					Index:  index,
+					Client: es,
+				})
+				bulkIndex(bi, 500)
+
+				bi, _ = esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
+					Index:  index,
+					Client: es,
+				})
+				bulkIndex(bi, 900)
+			})
+		})
+	}
+}
diff --git a/esutil/bulk_indexer_internal_test.go b/esutil/bulk_indexer_internal_test.go
new file mode 100644
index 0000000000..ade7c2e5b5
--- /dev/null
+++ b/esutil/bulk_indexer_internal_test.go
@@ -0,0 +1,856 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package esutil
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+var infoBody = `{
+  "version" : {
+	"number" : "7.14.0-SNAPSHOT",
+	"build_flavor" : "default"
+  },
+  "tagline" : "You Know, for Search"
+}`
+
+var defaultRoundTripFunc = func(*http.Request) (*http.Response, error) {
+	return &http.Response{Body: ioutil.NopCloser(strings.NewReader(`{}`))}, nil
+}
+
+type mockTransport struct {
+	RoundTripFunc func(*http.Request) (*http.Response, error)
+}
+
+func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	if t.RoundTripFunc == nil {
+		return defaultRoundTripFunc(req)
+	}
+	return t.RoundTripFunc(req)
+}
+
+func TestBulkIndexer(t *testing.T) {
+	t.Run("Basic", func(t *testing.T) {
+		var (
+			wg sync.WaitGroup
+
+			countReqs int
+			testfile  string
+			numItems  = 6
+		)
+
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{
+			RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+				if request.URL.Path == "/" {
+					return &http.Response{Header: http.Header{"Content-Type": []string{"application/json"}}, Body: ioutil.NopCloser(strings.NewReader(infoBody))}, nil
+				}
+
+				countReqs++
+				switch countReqs {
+				case 1:
+					testfile = "testdata/bulk_response_1a.json"
+				case 2:
+					testfile = "testdata/bulk_response_1b.json"
+				case 3:
+					testfile = "testdata/bulk_response_1c.json"
+				}
+				bodyContent, _ := ioutil.ReadFile(testfile)
+				return &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer(bodyContent))}, nil
+			},
+		}})
+
+		cfg := BulkIndexerConfig{
+			NumWorkers:    1,
+			FlushBytes:    50,
+			FlushInterval: time.Hour, // Disable auto-flushing, because response doesn't match number of items
+			Client:        es}
+		if os.Getenv("DEBUG") != "" {
+			cfg.DebugLogger = log.New(os.Stdout, "", 0)
+		}
+
+		bi, _ := NewBulkIndexer(cfg)
+
+		for i := 1; i <= numItems; i++ {
+			wg.Add(1)
+			go func(i int) {
+				defer wg.Done()
+				err := bi.Add(context.Background(), BulkIndexerItem{
+					Action:     "foo",
+					DocumentID: strconv.Itoa(i),
+					Body:       strings.NewReader(fmt.Sprintf(`{"title":"foo-%d"}`, i)),
+				})
+				if err != nil {
+					t.Errorf("Unexpected error: %s", err)
+					return
+				}
+			}(i)
+		}
+		wg.Wait()
+
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		stats := bi.Stats()
+
+		// added = numitems
+		if stats.NumAdded != uint64(numItems) {
+			t.Errorf("Unexpected NumAdded: want=%d, got=%d", numItems, stats.NumAdded)
+		}
+
+		// flushed = numitems - 1x conflict + 1x not_found
+		if stats.NumFlushed != uint64(numItems-2) {
+			t.Errorf("Unexpected NumFlushed: want=%d, got=%d", numItems-2, stats.NumFlushed)
+		}
+
+		// failed = 1x conflict + 1x not_found
+		if stats.NumFailed != 2 {
+			t.Errorf("Unexpected NumFailed: want=%d, got=%d", 2, stats.NumFailed)
+		}
+
+		// indexed = 1x
+		if stats.NumIndexed != 1 {
+			t.Errorf("Unexpected NumIndexed: want=%d, got=%d", 1, stats.NumIndexed)
+		}
+
+		// created = 1x
+		if stats.NumCreated != 1 {
+			t.Errorf("Unexpected NumCreated: want=%d, got=%d", 1, stats.NumCreated)
+		}
+
+		// deleted = 1x
+		if stats.NumDeleted != 1 {
+			t.Errorf("Unexpected NumDeleted: want=%d, got=%d", 1, stats.NumDeleted)
+		}
+
+		if stats.NumUpdated != 1 {
+			t.Errorf("Unexpected NumUpdated: want=%d, got=%d", 1, stats.NumUpdated)
+		}
+
+		// 3 items * 40 bytes, 2 workers, 1 request per worker
+		if stats.NumRequests != 3 {
+			t.Errorf("Unexpected NumRequests: want=%d, got=%d", 3, stats.NumRequests)
+		}
+	})
+
+	t.Run("Add() Timeout", func(t *testing.T) {
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{}})
+		bi, _ := NewBulkIndexer(BulkIndexerConfig{NumWorkers: 1, Client: es})
+		ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
+		defer cancel()
+		time.Sleep(100 * time.Millisecond)
+
+		var errs []error
+		for i := 0; i < 10; i++ {
+			errs = append(errs, bi.Add(ctx, BulkIndexerItem{Action: "delete", DocumentID: "timeout"}))
+		}
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		var gotError bool
+		for _, err := range errs {
+			if err != nil && err.Error() == "context deadline exceeded" {
+				gotError = true
+			}
+		}
+		if !gotError {
+			t.Errorf("Expected timeout error, but none in: %q", errs)
+		}
+	})
+
+	t.Run("Close() Cancel", func(t *testing.T) {
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{}})
+		bi, _ := NewBulkIndexer(BulkIndexerConfig{
+			NumWorkers: 1,
+			FlushBytes: 1,
+			Client:     es,
+		})
+
+		for i := 0; i < 10; i++ {
+			bi.Add(context.Background(), BulkIndexerItem{Action: "foo"})
+		}
+
+		ctx, cancel := context.WithCancel(context.Background())
+		cancel()
+		if err := bi.Close(ctx); err == nil {
+			t.Errorf("Expected context cancelled error, but got: %v", err)
+		}
+	})
+
+	t.Run("Indexer Callback", func(t *testing.T) {
+		esCfg := elasticsearch.Config{
+			Transport: &mockTransport{
+				RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+					if request.URL.Path == "/" {
+						return &http.Response{Body: ioutil.NopCloser(strings.NewReader(infoBody))}, nil
+					}
+
+					return nil, fmt.Errorf("Mock transport error")
+				},
+			},
+		}
+		if os.Getenv("DEBUG") != "" {
+			esCfg.Logger = &estransport.ColorLogger{
+				Output:             os.Stdout,
+				EnableRequestBody:  true,
+				EnableResponseBody: true,
+			}
+		}
+
+		es, _ := elasticsearch.NewClient(esCfg)
+
+		var indexerError error
+		biCfg := BulkIndexerConfig{
+			NumWorkers: 1,
+			Client:     es,
+			OnError:    func(ctx context.Context, err error) { indexerError = err },
+		}
+		if os.Getenv("DEBUG") != "" {
+			biCfg.DebugLogger = log.New(os.Stdout, "", 0)
+		}
+
+		bi, _ := NewBulkIndexer(biCfg)
+
+		if err := bi.Add(context.Background(), BulkIndexerItem{
+			Action: "foo",
+		}); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		bi.Close(context.Background())
+
+		if indexerError == nil {
+			t.Errorf("Expected indexerError to not be nil")
+		}
+	})
+
+	t.Run("Item Callbacks", func(t *testing.T) {
+		var (
+			countSuccessful      uint64
+			countFailed          uint64
+			failedIDs            []string
+			successfulItemBodies []string
+			failedItemBodies     []string
+
+			numItems       = 4
+			numFailed      = 2
+			bodyContent, _ = ioutil.ReadFile("testdata/bulk_response_2.json")
+		)
+
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{
+			RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+				if request.URL.Path == "/" {
+					return &http.Response{
+						StatusCode: http.StatusOK,
+						Status:     "200 OK",
+						Body:       ioutil.NopCloser(strings.NewReader(`{
+						  "version" : {
+							"number" : "7.14.0-SNAPSHOT",
+							"build_flavor" : "default"
+						  },
+						  "tagline" : "You Know, for Search"
+						}`)),
+						Header: http.Header{"Content-Type": []string{"application/json"}},
+					}, nil
+				}
+
+				return &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer(bodyContent))}, nil
+			},
+		}})
+
+		cfg := BulkIndexerConfig{NumWorkers: 1, Client: es}
+		if os.Getenv("DEBUG") != "" {
+			cfg.DebugLogger = log.New(os.Stdout, "", 0)
+		}
+
+		bi, _ := NewBulkIndexer(cfg)
+
+		successFunc := func(ctx context.Context, item BulkIndexerItem, res BulkIndexerResponseItem) {
+			atomic.AddUint64(&countSuccessful, 1)
+
+			buf, err := ioutil.ReadAll(item.Body)
+			if err != nil {
+				t.Fatalf("Unexpected error: %s", err)
+			}
+			successfulItemBodies = append(successfulItemBodies, string(buf))
+		}
+		failureFunc := func(ctx context.Context, item BulkIndexerItem, res BulkIndexerResponseItem, err error) {
+			atomic.AddUint64(&countFailed, 1)
+			failedIDs = append(failedIDs, item.DocumentID)
+
+			buf, err := ioutil.ReadAll(item.Body)
+			if err != nil {
+				t.Fatalf("Unexpected error: %s", err)
+			}
+			failedItemBodies = append(failedItemBodies, string(buf))
+		}
+
+		if err := bi.Add(context.Background(), BulkIndexerItem{
+			Action:     "index",
+			DocumentID: "1",
+			Body:       strings.NewReader(`{"title":"foo"}`),
+			OnSuccess:  successFunc,
+			OnFailure:  failureFunc,
+		}); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Add(context.Background(), BulkIndexerItem{
+			Action:     "create",
+			DocumentID: "1",
+			Body:       strings.NewReader(`{"title":"bar"}`),
+			OnSuccess:  successFunc,
+			OnFailure:  failureFunc,
+		}); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Add(context.Background(), BulkIndexerItem{
+			Action:     "delete",
+			DocumentID: "2",
+			Body:       strings.NewReader(`{"title":"baz"}`),
+			OnSuccess:  successFunc,
+			OnFailure:  failureFunc,
+		}); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Add(context.Background(), BulkIndexerItem{
+			Action:     "update",
+			DocumentID: "3",
+			Body:       strings.NewReader(`{"doc":{"title":"qux"}}`),
+			OnSuccess:  successFunc,
+			OnFailure:  failureFunc,
+		}); err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		stats := bi.Stats()
+
+		if stats.NumAdded != uint64(numItems) {
+			t.Errorf("Unexpected NumAdded: %d", stats.NumAdded)
+		}
+
+		// Two failures are expected:
+		//
+		// * Operation #2: document can't be created, because a document with the same ID already exists.
+		// * Operation #3: document can't be deleted, because it doesn't exist.
+
+		if stats.NumFailed != uint64(numFailed) {
+			t.Errorf("Unexpected NumFailed: %d", stats.NumFailed)
+		}
+
+		if stats.NumFlushed != 2 {
+			t.Errorf("Unexpected NumFailed: %d", stats.NumFailed)
+		}
+
+		if stats.NumIndexed != 1 {
+			t.Errorf("Unexpected NumIndexed: %d", stats.NumIndexed)
+		}
+
+		if stats.NumUpdated != 1 {
+			t.Errorf("Unexpected NumUpdated: %d", stats.NumUpdated)
+		}
+
+		if countSuccessful != uint64(numItems-numFailed) {
+			t.Errorf("Unexpected countSuccessful: %d", countSuccessful)
+		}
+
+		if countFailed != uint64(numFailed) {
+			t.Errorf("Unexpected countFailed: %d", countFailed)
+		}
+
+		if !reflect.DeepEqual(failedIDs, []string{"1", "2"}) {
+			t.Errorf("Unexpected failedIDs: %#v", failedIDs)
+		}
+
+		if !reflect.DeepEqual(successfulItemBodies, []string{`{"title":"foo"}`, `{"doc":{"title":"qux"}}`}) {
+			t.Errorf("Unexpected successfulItemBodies: %#v", successfulItemBodies)
+		}
+
+		if !reflect.DeepEqual(failedItemBodies, []string{`{"title":"bar"}`, `{"title":"baz"}`}) {
+			t.Errorf("Unexpected failedItemBodies: %#v", failedItemBodies)
+		}
+	})
+
+	t.Run("OnFlush callbacks", func(t *testing.T) {
+		type contextKey string
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{}})
+		bi, _ := NewBulkIndexer(BulkIndexerConfig{
+			Client: es,
+			Index:  "foo",
+			OnFlushStart: func(ctx context.Context) context.Context {
+				fmt.Println(">>> Flush started")
+				return context.WithValue(ctx, contextKey("start"), time.Now().UTC())
+			},
+			OnFlushEnd: func(ctx context.Context) {
+				var duration time.Duration
+				if v := ctx.Value("start"); v != nil {
+					duration = time.Since(v.(time.Time))
+				}
+				fmt.Printf(">>> Flush finished (duration: %s)\n", duration)
+			},
+		})
+
+		err := bi.Add(context.Background(), BulkIndexerItem{
+			Action: "index",
+			Body:   strings.NewReader(`{"title":"foo"}`),
+		})
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		stats := bi.Stats()
+
+		if stats.NumAdded != uint64(1) {
+			t.Errorf("Unexpected NumAdded: %d", stats.NumAdded)
+		}
+	})
+
+	t.Run("Automatic flush", func(t *testing.T) {
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{
+			RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+				if request.URL.Path == "/" {
+					return &http.Response{
+						StatusCode: http.StatusOK,
+						Status:     "200 OK",
+						Body:       ioutil.NopCloser(strings.NewReader(`{
+						  "version" : {
+							"number" : "7.14.0-SNAPSHOT",
+							"build_flavor" : "default"
+						  },
+						  "tagline" : "You Know, for Search"
+						}`)),
+						Header: http.Header{"Content-Type": []string{"application/json"}},
+					}, nil
+				}
+
+				return &http.Response{
+					StatusCode: http.StatusOK,
+					Status:     "200 OK",
+					Body:       ioutil.NopCloser(strings.NewReader(`{"items":[{"index": {}}]}`))}, nil
+			},
+		}})
+
+		cfg := BulkIndexerConfig{
+			NumWorkers:    1,
+			Client:        es,
+			FlushInterval: 50 * time.Millisecond, // Decrease the flush timeout
+		}
+		if os.Getenv("DEBUG") != "" {
+			cfg.DebugLogger = log.New(os.Stdout, "", 0)
+		}
+
+		bi, _ := NewBulkIndexer(cfg)
+
+		bi.Add(context.Background(),
+			BulkIndexerItem{Action: "index", Body: strings.NewReader(`{"title":"foo"}`)})
+
+		// Allow some time for auto-flush to kick in
+		time.Sleep(250 * time.Millisecond)
+
+		stats := bi.Stats()
+		expected := uint64(1)
+
+		if stats.NumAdded != expected {
+			t.Errorf("Unexpected NumAdded: want=%d, got=%d", expected, stats.NumAdded)
+		}
+
+		if stats.NumFailed != 0 {
+			t.Errorf("Unexpected NumFailed: want=%d, got=%d", 0, stats.NumFlushed)
+		}
+
+		if stats.NumFlushed != expected {
+			t.Errorf("Unexpected NumFlushed: want=%d, got=%d", expected, stats.NumFlushed)
+		}
+
+		if stats.NumIndexed != expected {
+			t.Errorf("Unexpected NumIndexed: want=%d, got=%d", expected, stats.NumIndexed)
+		}
+
+		// Wait some time before closing the indexer to clear the timer
+		time.Sleep(200 * time.Millisecond)
+		bi.Close(context.Background())
+	})
+
+	t.Run("TooManyRequests", func(t *testing.T) {
+		var (
+			wg sync.WaitGroup
+
+			countReqs int
+			numItems  = 2
+		)
+
+		esCfg := elasticsearch.Config{
+			Transport: &mockTransport{
+				RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+					if request.URL.Path == "/" {
+						return &http.Response{
+							StatusCode: http.StatusOK,
+							Status:     "200 OK",
+							Body:       ioutil.NopCloser(strings.NewReader(`{
+						  "version" : {
+							"number" : "7.14.0-SNAPSHOT",
+							"build_flavor" : "default"
+						  },
+						  "tagline" : "You Know, for Search"
+						}`)),
+							Header: http.Header{"Content-Type": []string{"application/json"}},
+						}, nil
+					}
+
+					countReqs++
+					if countReqs <= 4 {
+						return &http.Response{
+							StatusCode: http.StatusTooManyRequests,
+							Status:     "429 TooManyRequests",
+							Body:       ioutil.NopCloser(strings.NewReader(`{"took":1}`))}, nil
+					}
+					bodyContent, _ := ioutil.ReadFile("testdata/bulk_response_1c.json")
+					return &http.Response{
+						StatusCode: http.StatusOK,
+						Status:     "200 OK",
+						Body:       ioutil.NopCloser(bytes.NewBuffer(bodyContent)),
+					}, nil
+				},
+			},
+
+			MaxRetries:    5,
+			RetryOnStatus: []int{502, 503, 504, 429},
+			RetryBackoff: func(i int) time.Duration {
+				if os.Getenv("DEBUG") != "" {
+					fmt.Printf("*** Retry #%d\n", i)
+				}
+				return time.Duration(i) * 100 * time.Millisecond
+			},
+		}
+		if os.Getenv("DEBUG") != "" {
+			esCfg.Logger = &estransport.ColorLogger{Output: os.Stdout}
+		}
+		es, _ := elasticsearch.NewClient(esCfg)
+
+		biCfg := BulkIndexerConfig{NumWorkers: 1, FlushBytes: 50, Client: es}
+		if os.Getenv("DEBUG") != "" {
+			biCfg.DebugLogger = log.New(os.Stdout, "", 0)
+		}
+
+		bi, _ := NewBulkIndexer(biCfg)
+
+		for i := 1; i <= numItems; i++ {
+			wg.Add(1)
+			go func(i int) {
+				defer wg.Done()
+				err := bi.Add(context.Background(), BulkIndexerItem{
+					Action: "foo",
+					Body:   strings.NewReader(`{"title":"foo"}`),
+				})
+				if err != nil {
+					t.Errorf("Unexpected error: %s", err)
+					return
+				}
+			}(i)
+		}
+		wg.Wait()
+
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		stats := bi.Stats()
+
+		if stats.NumAdded != uint64(numItems) {
+			t.Errorf("Unexpected NumAdded: want=%d, got=%d", numItems, stats.NumAdded)
+		}
+
+		if stats.NumFlushed != uint64(numItems) {
+			t.Errorf("Unexpected NumFlushed: want=%d, got=%d", numItems, stats.NumFlushed)
+		}
+
+		if stats.NumFailed != 0 {
+			t.Errorf("Unexpected NumFailed: want=%d, got=%d", 0, stats.NumFailed)
+		}
+
+		// Stats don't include the retries in client
+		if stats.NumRequests != 1 {
+			t.Errorf("Unexpected NumRequests: want=%d, got=%d", 3, stats.NumRequests)
+		}
+	})
+
+	t.Run("Custom JSON Decoder", func(t *testing.T) {
+		es, _ := elasticsearch.NewClient(elasticsearch.Config{Transport: &mockTransport{}})
+		bi, _ := NewBulkIndexer(BulkIndexerConfig{Client: es, Decoder: customJSONDecoder{}})
+
+		err := bi.Add(context.Background(), BulkIndexerItem{
+			Action:     "index",
+			DocumentID: "1",
+			Body:       strings.NewReader(`{"title":"foo"}`),
+		})
+		if err != nil {
+			t.Fatalf("Unexpected error: %s", err)
+		}
+
+		if err := bi.Close(context.Background()); err != nil {
+			t.Errorf("Unexpected error: %s", err)
+		}
+
+		stats := bi.Stats()
+
+		if stats.NumAdded != uint64(1) {
+			t.Errorf("Unexpected NumAdded: %d", stats.NumAdded)
+		}
+	})
+	t.Run("Worker.writeMeta()", func(t *testing.T) {
+		v:=int64(23)
+		type args struct {
+			item BulkIndexerItem
+		}
+		tests := []struct {
+			name string
+			args args
+			want string
+		}{
+			{
+				"without _index and _id",
+				args{BulkIndexerItem{Action: "index"}},
+				`{"index":{}}` + "\n",
+			},
+			{
+				"with _id",
+				args{BulkIndexerItem{
+					Action:     "index",
+					DocumentID: "42",
+				}},
+				`{"index":{"_id":"42"}}` + "\n",
+			},
+			{
+				"with _index",
+				args{BulkIndexerItem{
+					Action: "index",
+					Index:  "test",
+				}},
+				`{"index":{"_index":"test"}}` + "\n",
+			},
+			{
+				"with _index and _id",
+				args{BulkIndexerItem{
+					Action:     "index",
+					DocumentID: "42",
+					Index:      "test",
+				}},
+				`{"index":{"_id":"42","_index":"test"}}` + "\n",
+			},
+			{
+				"with version and no document",
+				args{BulkIndexerItem{
+					Action:     "index",
+					Index:      "test",
+					Version:    &v,
+				}},
+				`{"index":{"_index":"test"}}` + "\n",
+			},
+			{
+				"with version",
+				args{BulkIndexerItem{
+					Action:     "index",
+					DocumentID: "42",
+					Index:      "test",
+					Version:    &v,
+				}},
+				`{"index":{"_id":"42","version":23,"_index":"test"}}` + "\n",
+			},
+			{
+				"with version and version_type",
+				args{BulkIndexerItem{
+					Action:      "index",
+					DocumentID:  "42",
+					Index:       "test",
+					Version:     &v,
+					VersionType: "external",
+				}},
+				`{"index":{"_id":"42","version":23,"version_type":"external","_index":"test"}}` + "\n",
+			},
+		}
+		for _, tt := range tests {
+			tt := tt
+
+			t.Run(tt.name, func(t *testing.T) {
+				w := &worker{
+					buf: bytes.NewBuffer(make([]byte, 0, 5e+6)),
+					aux: make([]byte, 0, 512),
+				}
+				if err := w.writeMeta(tt.args.item); err != nil {
+					t.Errorf("Unexpected error: %v", err)
+				}
+
+				if w.buf.String() != tt.want {
+					t.Errorf("worker.writeMeta() %s = got [%s], want [%s]", tt.name, w.buf.String(), tt.want)
+				}
+
+			})
+		}
+	})
+
+	t.Run("MetaHeader presence in Request header", func(t *testing.T) {
+		type args struct {
+			disableMetaHeader bool
+			header            http.Header
+		}
+		tests := []struct {
+			name string
+			args args
+			want string
+		}{
+			{
+				name: "Meta header is present in header",
+				args: args{
+					disableMetaHeader: false,
+				},
+				want: `^[a-z]{1,}=[a-z0-9\.\-]{1,}(?:,[a-z]{1,}=[a-z0-9\.\-]+)*,h=bp$`,
+			},
+			{
+				name: "Header should be empty of meta header",
+				args: args{
+					disableMetaHeader: true,
+				},
+				want: ``,
+			},
+			{
+				name: "User has set header",
+				args: args{
+					disableMetaHeader: false,
+					header: http.Header{
+						"X-Test-User": []string{"UserValue"},
+					},
+				},
+			},
+			{
+				name: "User should not temper with Meta Header",
+				args: args{
+					disableMetaHeader: false,
+					header: http.Header{
+						"X-Test-User":                []string{"UserValue"},
+						estransport.HeaderClientMeta: []string{"h=shouldntbechanged"},
+					},
+				},
+			},
+		}
+		for _, tt := range tests {
+			t.Run(tt.name, func(t *testing.T) {
+				reValidation := regexp.MustCompile(tt.want)
+
+				esConfig := elasticsearch.Config{
+					DisableMetaHeader: tt.args.disableMetaHeader,
+					Header:            tt.args.header,
+					Transport: &mockTransport{
+						RoundTripFunc: func(request *http.Request) (*http.Response, error) {
+							if request.URL.Path == "/" {
+								return &http.Response{
+									StatusCode: http.StatusOK,
+									Status:     "200 OK",
+									Body:       ioutil.NopCloser(strings.NewReader(infoBody)),
+								}, nil
+							}
+
+							headerMeta := request.Header.Get(estransport.HeaderClientMeta)
+
+							if !reValidation.MatchString(headerMeta) {
+								t.Errorf("Meta Header presence is invalid, got : %s, want : %s", headerMeta, tt.want)
+							}
+
+							if tt.args.disableMetaHeader && headerMeta != "" {
+								t.Errorf("Meta Header is disabled, should be empty, got : %s", headerMeta)
+							}
+
+							if tt.args.header != nil {
+								if userHeader := request.Header.Get("X-Test-User"); userHeader != "UserValue" {
+									t.Errorf("User header should be preserved, got : %s", userHeader)
+								}
+							}
+
+							return &http.Response{
+								StatusCode: http.StatusOK,
+								Status:     "200 OK",
+								Body:       ioutil.NopCloser(bytes.NewBuffer(nil)),
+							}, nil
+						},
+					},
+				}
+
+				client, err := elasticsearch.NewClient(esConfig)
+				if err != nil {
+					log.Fatal(err)
+				}
+
+				cfg := BulkIndexerConfig{
+					Client: client,
+					Header: tt.args.header,
+				}
+				bi, err := NewBulkIndexer(cfg)
+				if err != nil {
+					log.Fatal(err)
+				}
+
+				err = bi.Add(context.Background(), BulkIndexerItem{
+					Action:     "foo",
+					DocumentID: strconv.Itoa(1),
+					Body:       strings.NewReader(fmt.Sprintf(`{"title":"foo-%d"}`, 1)),
+				})
+				if err != nil {
+					log.Fatal(err)
+				}
+				bi.Close(context.Background())
+			})
+		}
+	})
+}
+
+type customJSONDecoder struct{}
+
+func (d customJSONDecoder) UnmarshalFromReader(r io.Reader, blk *BulkIndexerResponse) error {
+	return json.NewDecoder(r).Decode(blk)
+}
diff --git a/esutil/doc.go b/esutil/doc.go
new file mode 100644
index 0000000000..494a019e85
--- /dev/null
+++ b/esutil/doc.go
@@ -0,0 +1,22 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/*
+Package esutil provides helper utilities to the Go client for Elasticsearch.
+
+*/
+package esutil
diff --git a/esutil/json_reader.go b/esutil/json_reader.go
new file mode 100644
index 0000000000..36673a4ca4
--- /dev/null
+++ b/esutil/json_reader.go
@@ -0,0 +1,95 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package esutil
+
+import (
+	"bytes"
+	"encoding/json"
+	"io"
+)
+
+// NewJSONReader encodes v into JSON and returns it as an io.Reader.
+//
+func NewJSONReader(v interface{}) io.Reader {
+	return &JSONReader{val: v, buf: nil}
+}
+
+// JSONEncoder defines the interface for custom JSON encoders.
+//
+type JSONEncoder interface {
+	EncodeJSON(io.Writer) error
+}
+
+// JSONReader represents a reader which takes an interface value,
+// encodes it into JSON, and wraps it in an io.Reader.
+//
+type JSONReader struct {
+	val interface{}
+	buf interface {
+		io.ReadWriter
+		io.WriterTo
+	}
+}
+
+// Read implements the io.Reader interface.
+//
+func (r *JSONReader) Read(p []byte) (int, error) {
+	if r.buf == nil {
+		r.buf = new(bytes.Buffer)
+		if err := r.encode(r.buf); err != nil {
+			return 0, err
+		}
+	}
+
+	return r.buf.Read(p)
+}
+
+// WriteTo implements the io.WriterTo interface.
+//
+func (r *JSONReader) WriteTo(w io.Writer) (int64, error) {
+	cw := countingWriter{Writer: w}
+	err := r.encode(&cw)
+	return int64(cw.n), err
+}
+
+func (r *JSONReader) encode(w io.Writer) error {
+	var err error
+
+	if e, ok := r.val.(JSONEncoder); ok {
+		err = e.EncodeJSON(w)
+		if err != nil {
+			return err
+		}
+		return nil
+	}
+
+	return json.NewEncoder(w).Encode(r.val)
+}
+
+type countingWriter struct {
+	io.Writer
+	n int
+}
+
+func (cw *countingWriter) Write(p []byte) (int, error) {
+	n, err := cw.Writer.Write(p)
+	if n > 0 {
+		cw.n += n
+	}
+	return n, err
+}
diff --git a/esutil/json_reader_benchmark_test.go b/esutil/json_reader_benchmark_test.go
new file mode 100644
index 0000000000..0f61a44813
--- /dev/null
+++ b/esutil/json_reader_benchmark_test.go
@@ -0,0 +1,103 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package esutil_test
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+var _ = fmt.Print
+
+type Foo struct {
+	Bar string
+}
+
+func (f Foo) EncodeJSON(w io.Writer) error {
+	var b bytes.Buffer
+	b.WriteString(`{"bar":"`)
+	b.WriteString(strings.ToUpper(f.Bar))
+	b.WriteString(`"}`)
+	b.WriteString("\n")
+	_, err := b.WriteTo(w)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func BenchmarkJSONReader(b *testing.B) {
+	b.ReportAllocs()
+
+	b.Run("None", func(b *testing.B) {
+		b.ResetTimer()
+
+		var buf bytes.Buffer
+		for i := 0; i < b.N; i++ {
+			json.NewEncoder(&buf).Encode(map[string]string{"foo": "bar"})
+			if string(buf.String()) != `{"foo":"bar"}`+"\n" {
+				b.Fatalf("Unexpected output: %q", buf.String())
+			}
+			buf.Reset()
+		}
+	})
+
+	b.Run("Default", func(b *testing.B) {
+		b.ResetTimer()
+
+		for i := 0; i < b.N; i++ {
+			out, _ := ioutil.ReadAll(esutil.NewJSONReader(map[string]string{"foo": "bar"}))
+			if string(out) != `{"foo":"bar"}`+"\n" {
+				b.Fatalf("Unexpected output: %q", out)
+			}
+		}
+	})
+
+	b.Run("Default-Copy", func(b *testing.B) {
+		b.ResetTimer()
+
+		var buf bytes.Buffer
+		for i := 0; i < b.N; i++ {
+			io.Copy(&buf, esutil.NewJSONReader(map[string]string{"foo": "bar"}))
+			if buf.String() != `{"foo":"bar"}`+"\n" {
+				b.Fatalf("Unexpected output: %q", buf.String())
+			}
+			buf.Reset()
+		}
+	})
+
+	b.Run("Custom", func(b *testing.B) {
+		b.ResetTimer()
+
+		for i := 0; i < b.N; i++ {
+			out, _ := ioutil.ReadAll(esutil.NewJSONReader(Foo{Bar: "baz"}))
+			if string(out) != `{"bar":"BAZ"}`+"\n" {
+				b.Fatalf("Unexpected output: %q", out)
+			}
+		}
+	})
+}
diff --git a/esutil/json_reader_integration_test.go b/esutil/json_reader_integration_test.go
new file mode 100644
index 0000000000..d7fecc94da
--- /dev/null
+++ b/esutil/json_reader_integration_test.go
@@ -0,0 +1,85 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build integration
+
+package esutil_test
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/esutil"
+)
+
+func TestJSONReaderIntegration(t *testing.T) {
+	t.Run("Index and search", func(t *testing.T) {
+		var (
+			res *esapi.Response
+			err error
+		)
+
+		es, err := elasticsearch.NewDefaultClient()
+		if err != nil {
+			t.Fatalf("Error creating the client: %s\n", err)
+		}
+
+		es.Indices.Delete([]string{"test"}, es.Indices.Delete.WithIgnoreUnavailable(true))
+
+		doc := struct {
+			Title string `json:"title"`
+		}{Title: "Foo Bar"}
+
+		res, err = es.Index("test", esutil.NewJSONReader(&doc), es.Index.WithRefresh("true"))
+		if err != nil {
+			t.Fatalf("Error getting response: %s", err)
+		}
+		defer res.Body.Close()
+
+		if res.IsError() {
+			t.Fatalf("Error response: %s", res.String())
+		}
+
+		query := map[string]interface{}{
+			"query": map[string]interface{}{
+				"match": map[string]interface{}{
+					"title": "foo",
+				},
+			},
+		}
+
+		res, err = es.Search(
+			es.Search.WithIndex("test"),
+			es.Search.WithBody(esutil.NewJSONReader(&query)),
+			es.Search.WithPretty(),
+		)
+		if err != nil {
+			t.Fatalf("Error getting response: %s", err)
+		}
+		defer res.Body.Close()
+
+		if res.IsError() {
+			t.Errorf("Error response: %s", res)
+		}
+
+		if !strings.Contains(res.String(), "Foo Bar") {
+			t.Errorf("Unexpected response: %s", res)
+		}
+	})
+}
diff --git a/esutil/json_reader_internal_test.go b/esutil/json_reader_internal_test.go
new file mode 100644
index 0000000000..642159c643
--- /dev/null
+++ b/esutil/json_reader_internal_test.go
@@ -0,0 +1,81 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// +build !integration
+
+package esutil
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+)
+
+type errReader struct{}
+
+func (errReader) Read(p []byte) (int, error)         { return 1, errors.New("MOCK ERROR") }
+func (errReader) Write(p []byte) (int, error)        { return 0, errors.New("MOCK ERROR") }
+func (errReader) WriteTo(w io.Writer) (int64, error) { return 0, errors.New("MOCK ERROR") }
+
+type Foo struct {
+	Bar string
+}
+
+func (f Foo) EncodeJSON(w io.Writer) error {
+	_, err := w.Write([]byte(`{"bar":"` + strings.ToUpper(f.Bar) + `"}` + "\n"))
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func TestJSONReader(t *testing.T) {
+	t.Run("Default", func(t *testing.T) {
+		out, _ := ioutil.ReadAll(NewJSONReader(map[string]string{"foo": "bar"}))
+		if string(out) != `{"foo":"bar"}`+"\n" {
+			t.Fatalf("Unexpected output: %s", out)
+		}
+	})
+
+	t.Run("Custom", func(t *testing.T) {
+		out, _ := ioutil.ReadAll(NewJSONReader(Foo{Bar: "baz"}))
+		if string(out) != `{"bar":"BAZ"}`+"\n" {
+			t.Fatalf("Unexpected output: %s", out)
+		}
+	})
+
+	t.Run("WriteTo", func(t *testing.T) {
+		b := bytes.NewBuffer([]byte{})
+		r := JSONReader{val: map[string]string{"foo": "bar"}}
+		r.WriteTo(b)
+		if b.String() != `{"foo":"bar"}`+"\n" {
+			t.Fatalf("Unexpected output: %s", b.String())
+		}
+	})
+
+	t.Run("Read error", func(t *testing.T) {
+		b := []byte{}
+		r := JSONReader{val: map[string]string{"foo": "bar"}, buf: errReader{}}
+		_, err := r.Read(b)
+		if err == nil {
+			t.Fatalf("Expected error, got: %#v", err)
+		}
+	})
+}
diff --git a/esutil/testdata/bulk_response_1a.json b/esutil/testdata/bulk_response_1a.json
new file mode 100644
index 0000000000..972a23add7
--- /dev/null
+++ b/esutil/testdata/bulk_response_1a.json
@@ -0,0 +1,36 @@
+{
+  "took": 30,
+  "errors": true,
+  "items": [
+    {
+      "index": {
+        "_index": "test",
+        "_id": "1",
+        "_version": 1,
+        "result": "created",
+        "_shards": {
+          "total": 1,
+          "successful": 1,
+          "failed": 0
+        },
+        "_seq_no": 0,
+        "_primary_term": 1,
+        "status": 201
+      }
+    },
+    {
+      "create": {
+        "_index": "test",
+        "_id": "2",
+        "status": 409,
+        "error": {
+          "type": "version_conflict_engine_exception",
+          "reason": "[1]: version conflict, document already exists (current version [1])",
+          "index_uuid": "eZMQ7DUzT56RLaQcAjOlxg",
+          "index": "test-bulk-integration",
+          "shard": "0"
+        }
+      }
+    }
+  ]
+}
diff --git a/esutil/testdata/bulk_response_1b.json b/esutil/testdata/bulk_response_1b.json
new file mode 100644
index 0000000000..3ffdffdcff
--- /dev/null
+++ b/esutil/testdata/bulk_response_1b.json
@@ -0,0 +1,38 @@
+{
+  "took": 30,
+  "errors": false,
+  "items": [
+    {
+      "create": {
+        "_index": "test",
+        "_id": "3",
+        "_version": 1,
+        "result": "created",
+        "status": 201,
+        "_shards": {
+          "total": 1,
+          "successful": 1,
+          "failed": 0
+        },
+        "_seq_no": 1,
+        "_primary_term": 2
+      }
+    },
+    {
+      "delete": {
+        "_index": "test",
+        "_id": "4",
+        "_version": 1,
+        "result": "not_found",
+        "_shards": {
+          "total": 1,
+          "successful": 1,
+          "failed": 0
+        },
+        "_seq_no": 0,
+        "_primary_term": 1,
+        "status": 404
+      }
+    }
+  ]
+}
diff --git a/esutil/testdata/bulk_response_1c.json b/esutil/testdata/bulk_response_1c.json
new file mode 100644
index 0000000000..39090d9e5e
--- /dev/null
+++ b/esutil/testdata/bulk_response_1c.json
@@ -0,0 +1,38 @@
+{
+  "took": 30,
+  "errors": false,
+  "items": [
+    {
+      "delete": {
+        "_index": "test",
+        "_id": "5",
+        "_version": 2,
+        "result": "deleted",
+        "status": 200,
+        "_shards": {
+          "total": 1,
+          "successful": 1,
+          "failed": 0
+        },
+        "_seq_no": 0,
+        "_primary_term": 1
+      }
+    },
+    {
+      "update": {
+        "_index": "test",
+        "_id": "6",
+        "_version": 2,
+        "result": "updated",
+        "_shards": {
+          "total": 1,
+          "successful": 1,
+          "failed": 0
+        },
+        "_seq_no": 0,
+        "_primary_term": 1,
+        "status": 200
+      }
+    }
+  ]
+}
diff --git a/esutil/testdata/bulk_response_2.json b/esutil/testdata/bulk_response_2.json
new file mode 100644
index 0000000000..608375813b
--- /dev/null
+++ b/esutil/testdata/bulk_response_2.json
@@ -0,0 +1,56 @@
+{
+  "took": 30,
+  "errors": true,
+  "items": [
+    {
+      "index": {
+        "_index": "test",
+        "_id": "1",
+        "_version": 1,
+        "result": "created",
+        "_shards": { "total": 1, "successful": 1, "failed": 0 },
+        "_seq_no": 0,
+        "_primary_term": 1,
+        "status": 201
+      }
+    },
+    {
+      "create": {
+        "_index": "test",
+        "_id": "1",
+        "status": 409,
+        "error": {
+          "type": "version_conflict_engine_exception",
+          "reason": "[1]: version conflict, document already exists (current version [1])",
+          "index_uuid": "eZMQ7DUzT56RLaQcAjOlxg",
+          "index": "test-bulk-integration",
+          "shard": "0"
+        }
+      }
+    },
+    {
+      "delete": {
+        "_index": "test",
+        "_id": "2",
+        "_version": 1,
+        "result": "not_found",
+        "_shards": { "total": 1, "successful": 1, "failed": 0 },
+        "_seq_no": 3,
+        "_primary_term": 1,
+        "status": 404
+      }
+    },
+    {
+      "update": {
+        "_index": "test",
+        "_id": "3",
+        "_version": 2,
+        "result": "updated",
+        "_shards": { "total": 1, "successful": 1, "failed": 0 },
+        "_seq_no": 4,
+        "_primary_term": 1,
+        "status": 200
+      }
+    }
+  ]
+}
diff --git a/go.mod b/go.mod
index e8f1c42c26..6199ebca43 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
-module github.com/elastic/go-elasticsearch
+module github.com/elastic/go-elasticsearch/v7
 
 go 1.11
diff --git a/go.sum b/go.sum
deleted file mode 100755
index e69de29bb2..0000000000
diff --git a/internal/build/cmd/commands.go b/internal/build/cmd/commands.go
new file mode 100644
index 0000000000..73ae37976f
--- /dev/null
+++ b/internal/build/cmd/commands.go
@@ -0,0 +1,46 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cmd
+
+import (
+	"os"
+
+	"github.com/spf13/cobra"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+)
+
+var rootCmd = &cobra.Command{
+	Use:   "build",
+	Short: "Build tools for Elasticsearch client, helpers for CI, etc...",
+}
+
+// Execute launches the CLI application.
+//
+func Execute() {
+	if err := rootCmd.Execute(); err != nil {
+		utils.PrintErr(err)
+		os.Exit(1)
+	}
+}
+
+// RegisterCmd adds a command to rootCmd.
+//
+func RegisterCmd(cmd *cobra.Command) {
+	rootCmd.AddCommand(cmd)
+}
diff --git a/internal/build/cmd/generate/commands/genexamples/command.go b/internal/build/cmd/generate/commands/genexamples/command.go
new file mode 100644
index 0000000000..2cc69a24ec
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genexamples/command.go
@@ -0,0 +1,462 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genexamples
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"time"
+
+	"github.com/spf13/cobra"
+	"golang.org/x/tools/imports"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+)
+
+var (
+	inputSrc  *string
+	outputSrc *string
+	debugSrc  *bool
+	colorSrc  *bool
+	gofmtSrc  *bool
+
+	inputDoc  *string
+	outputDoc *string
+	debugDoc  *bool
+)
+
+func init() {
+	inputSrc = genexamplesSrcCmd.Flags().StringP("input", "i", "", "Path to a file with specification for examples")
+	outputSrc = genexamplesSrcCmd.Flags().StringP("output", "o", "", "Path to a folder for generated output")
+	debugSrc = genexamplesSrcCmd.Flags().BoolP("debug", "d", false, "Print the generated source to terminal")
+	colorSrc = genexamplesSrcCmd.Flags().BoolP("color", "c", true, "Syntax highlight the debug output")
+	gofmtSrc = genexamplesSrcCmd.Flags().BoolP("gofmt", "f", true, "Format generated output with 'gofmt'")
+
+	genexamplesSrcCmd.MarkFlagRequired("input")
+	genexamplesSrcCmd.MarkFlagRequired("output")
+	genexamplesSrcCmd.Flags().SortFlags = false
+
+	inputDoc = genexamplesDocCmd.Flags().StringP("input", "i", "", "Path to a file with specification for examples")
+	outputDoc = genexamplesDocCmd.Flags().StringP("output", "o", "", "Path to a folder for generated output")
+	debugDoc = genexamplesDocCmd.Flags().BoolP("debug", "d", false, "Print the generated source to terminal")
+
+	genexamplesDocCmd.MarkFlagRequired("input")
+	genexamplesDocCmd.MarkFlagRequired("output")
+	genexamplesDocCmd.Flags().SortFlags = false
+
+	genexamplesCmd.AddCommand(genexamplesSrcCmd)
+	genexamplesCmd.AddCommand(genexamplesDocCmd)
+
+	cmd.RegisterCmd(genexamplesCmd)
+}
+
+var genexamplesCmd = &cobra.Command{
+	Use:   "examples",
+	Short: "Generate the Go examples for documentation",
+}
+
+var genexamplesSrcCmd = &cobra.Command{
+	Use:   "src",
+	Short: "Generate the Go sources for examples",
+	Run: func(cmd *cobra.Command, args []string) {
+		command := &SrcCommand{
+			Input:          *inputSrc,
+			Output:         *outputSrc,
+			DebugSource:    *debugSrc,
+			ColorizeSource: *colorSrc,
+			GofmtSource:    *gofmtSrc,
+		}
+		if err := command.Execute(); err != nil {
+			utils.PrintErr(err)
+			os.Exit(1)
+		}
+	},
+}
+
+var genexamplesDocCmd = &cobra.Command{
+	Use:   "doc",
+	Short: "Generate the ASCIIDoc examples",
+	Run: func(cmd *cobra.Command, args []string) {
+		command := &DocCommand{Input: *inputDoc, Output: *outputDoc, DebugSource: *debugDoc}
+		if err := command.Execute(); err != nil {
+			utils.PrintErr(err)
+			os.Exit(1)
+		}
+	},
+}
+
+// SrcCommand represents the command for generating Go source code.
+//
+type SrcCommand struct {
+	Input          string
+	Output         string
+	DebugSource    bool
+	ColorizeSource bool
+	GofmtSource    bool
+}
+
+// DocCommand represents the command for generating ASCIIDoc examples.
+//
+type DocCommand struct {
+	Input       string
+	Output      string
+	DebugSource bool
+}
+
+// Execute runs the command.
+//
+func (cmd *SrcCommand) Execute() error {
+	var (
+		processed  int
+		skipped    int
+		translated int
+		start      = time.Now()
+		seen       = make(map[string]bool)
+	)
+
+	if cmd.Output != "-" {
+		outputDir := filepath.Join(cmd.Output, "src")
+		if err := os.MkdirAll(outputDir, 0775); err != nil {
+			return fmt.Errorf("error creating output directory %q: %s", outputDir, err)
+		}
+	}
+
+	f, err := os.Open(cmd.Input)
+	if err != nil {
+		return fmt.Errorf("error reading input: %s", err)
+	}
+	defer f.Close()
+
+	var examples []Example
+	if err := json.NewDecoder(f).Decode(&examples); err != nil {
+		return fmt.Errorf("error decoding input: %s", err)
+	}
+
+	for _, e := range examples {
+		if !e.IsEnabled() || !e.IsExecutable() {
+			skipped++
+			continue
+		}
+
+		if seen[e.Digest] {
+			continue
+		}
+
+		var shouldSkip bool
+		for _, pat := range skipPatterns {
+			matched, _ := regexp.MatchString(pat, e.Source)
+			if matched {
+				skipped++
+				shouldSkip = true
+			}
+		}
+		if shouldSkip {
+			if utils.IsTTY() {
+				fmt.Fprint(os.Stderr, "\x1b[2m")
+			}
+			fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+			fmt.Fprintf(os.Stderr, "Skipping example %q @ %s\n", e.ID(), e.Digest)
+			if utils.IsTTY() {
+				fmt.Fprint(os.Stderr, "\x1b[0m")
+			}
+			skipped++
+			continue
+		}
+
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[2m")
+		}
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		fmt.Fprintf(os.Stderr, "Processing example %q @ %s\n", e.ID(), e.Digest)
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[0m")
+		}
+		if err := cmd.processExample(e); err != nil {
+			return fmt.Errorf("error processing example %s: %v", e.ID(), err)
+		}
+		processed++
+		if e.IsTranslated() {
+			translated++
+		}
+		seen[e.Digest] = true
+	}
+
+	if utils.IsTTY() {
+		fmt.Fprint(os.Stderr, "\x1b[2m")
+	}
+	fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+	fmt.Fprintf(
+		os.Stderr,
+		"Processed %d examples, translated %d, skipped %d examples in %s\n",
+		processed,
+		translated,
+		skipped,
+		time.Since(start).Truncate(time.Millisecond))
+	if utils.IsTTY() {
+		fmt.Fprint(os.Stderr, "\x1b[0m")
+	}
+
+	return nil
+}
+
+func (cmd *SrcCommand) processExample(e Example) error {
+	g := SrcGenerator{Example: e}
+	fName := filepath.Join(cmd.Output, "src", g.Filename())
+	out, err := g.Output()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		fmt.Fprintln(os.Stderr, e.Source)
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		return err
+	}
+
+	if cmd.GofmtSource {
+		var buf bytes.Buffer
+		buf.ReadFrom(out)
+
+		bout, err := imports.Process(
+			"example_test.go",
+			buf.Bytes(),
+			&imports.Options{
+				AllErrors:  true,
+				Comments:   true,
+				FormatOnly: false,
+				TabIndent:  true,
+				TabWidth:   1,
+			})
+		if err != nil {
+			if cmd.DebugSource {
+				utils.PrintSourceWithErr(&buf, err)
+			}
+			return err
+		}
+
+		out = bytes.NewBuffer(bout)
+	}
+
+	if cmd.DebugSource {
+		var (
+			err error
+			buf bytes.Buffer
+			src io.Reader
+			tee = io.TeeReader(out, &buf)
+		)
+
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[2m")
+		}
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[0m")
+		}
+
+		if cmd.ColorizeSource {
+			src, err = utils.Chromatize(tee)
+			if err != nil {
+				return fmt.Errorf("error syntax highligting the output: %s", err)
+			}
+
+			_, err = io.Copy(os.Stderr, src)
+			if err != nil {
+				return fmt.Errorf("error copying output: %s", err)
+			}
+		}
+
+		if _, err = io.Copy(os.Stderr, tee); err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+
+		fmt.Fprintf(os.Stderr, "\n\n")
+
+		out = &buf
+	}
+
+	if cmd.Output == "-" {
+		if _, err := io.Copy(os.Stdout, out); err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+	} else {
+		f, err := os.OpenFile(fName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+		if err != nil {
+			return fmt.Errorf("error creating file: %s", err)
+		}
+		if _, err = io.Copy(f, out); err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+		if err := f.Close(); err != nil {
+			return fmt.Errorf("error closing file: %s", err)
+		}
+	}
+
+	return nil
+}
+
+// Execute runs the command.
+//
+func (cmd *DocCommand) Execute() error {
+	var (
+		processed int
+		start     = time.Now()
+	)
+
+	if cmd.Output != "-" {
+		outputDir := filepath.Join(cmd.Output, "doc")
+		if err := os.MkdirAll(outputDir, 0775); err != nil {
+			return fmt.Errorf("error creating output directory %q: %s", outputDir, err)
+		}
+	}
+
+	files, err := ioutil.ReadDir(cmd.Input)
+	if err != nil {
+		return fmt.Errorf("failed to read input: %s", err)
+	}
+
+	for _, fi := range files {
+		if !strings.HasSuffix(fi.Name(), ".go") {
+			continue
+		}
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[2m")
+		}
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		fmt.Fprintf(os.Stderr, "Processing file %s\n", fi.Name())
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[0m")
+		}
+
+		f, err := os.Open(filepath.Join(cmd.Input, fi.Name()))
+		if err != nil {
+			return fmt.Errorf("error reading file: %s", err)
+		}
+		defer f.Close()
+
+		if err := cmd.processFile(f); err != nil {
+			return fmt.Errorf("error processing file %q: %s", fi.Name(), err)
+		}
+		processed++
+	}
+
+	if utils.IsTTY() {
+		fmt.Fprint(os.Stderr, "\x1b[2m")
+	}
+	fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+	fmt.Fprintf(
+		os.Stderr,
+		"Processed %d examples examples in %s\n",
+		processed,
+		time.Since(start).Truncate(time.Millisecond))
+	if utils.IsTTY() {
+		fmt.Fprint(os.Stderr, "\x1b[0m")
+	}
+
+	return nil
+}
+
+func (cmd *DocCommand) processFile(f *os.File) error {
+	var (
+		src bytes.Buffer
+
+		sc         = bufio.NewScanner(f)
+		reBegin    = regexp.MustCompile(`^\s?// tag:(\w+)\s?`)
+		reEnd      = regexp.MustCompile(`^\s?// end:\w+\s?`)
+		reSkip     = regexp.MustCompile(`// SKIP$`)
+		digest     string
+		capture    bool
+		outputFile string
+	)
+
+	for sc.Scan() {
+		line := sc.Text()
+
+		if reBegin.MatchString(line) {
+			digest = reBegin.FindStringSubmatch(line)[1]
+			capture = true
+		}
+		if reEnd.MatchString(line) {
+			capture = false
+		}
+
+		if capture && !reBegin.MatchString(line) && !reSkip.MatchString(line) {
+			line = strings.TrimPrefix(line, "\t")
+			src.WriteString(line)
+			src.WriteString("\n")
+		}
+	}
+
+	if err := sc.Err(); err != nil {
+		return err
+	}
+
+	out, err := DocGenerator{
+		Source:   &src,
+		Filename: filepath.Base(f.Name()),
+		Digest:   digest,
+	}.Output()
+	if err != nil {
+		return fmt.Errorf("error generating output: %s", err)
+	}
+
+	if cmd.DebugSource {
+		var buf bytes.Buffer
+		tee := io.TeeReader(out, &buf)
+
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[2m")
+		}
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[0m")
+		}
+		_, err = io.Copy(os.Stderr, tee)
+		if err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+
+		out = &buf
+	}
+
+	if cmd.Output == "-" {
+		if _, err := io.Copy(os.Stdout, out); err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+	} else {
+		outputFile = filepath.Join(cmd.Output, "doc", digest+".asciidoc")
+
+		f, err := os.OpenFile(outputFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+		if err != nil {
+			return fmt.Errorf("error creating file: %s", err)
+		}
+		if _, err = io.Copy(f, out); err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+		if err := f.Close(); err != nil {
+			return fmt.Errorf("error closing file: %s", err)
+		}
+	}
+
+	return nil
+}
diff --git a/internal/build/cmd/generate/commands/genexamples/generator.go b/internal/build/cmd/generate/commands/genexamples/generator.go
new file mode 100644
index 0000000000..746516f063
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genexamples/generator.go
@@ -0,0 +1,137 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genexamples
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"strings"
+)
+
+// SrcGenerator represents the generator for Go source files.
+//
+type SrcGenerator struct {
+	b       bytes.Buffer
+	Example Example
+}
+
+// DocGenerator represents the generator for Go source files.
+//
+type DocGenerator struct {
+	b        bytes.Buffer
+	Source   io.Reader
+	Filename string
+	Digest   string
+}
+
+func (g SrcGenerator) Filename() string {
+	return fmt.Sprintf(
+		"%s_%s_test.go",
+		strings.ReplaceAll(strings.TrimSuffix(g.Example.SourceLocation.File, ".asciidoc"), "/", "-"),
+		g.Example.Digest)
+}
+
+func (g SrcGenerator) Output() (io.Reader, error) {
+	var out bytes.Buffer
+
+	out.WriteString(`// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// Code generated, DO NOT EDIT
+
+package elasticsearch_test
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v8"
+)
+
+var (
+	_ = fmt.Printf
+	_ = os.Stdout
+	_ = elasticsearch.NewDefaultClient
+)
+
+`)
+
+	fmt.Fprintf(&out, "// <%s>\n//\n", g.Example.GithubURL())
+	out.WriteString("// " + strings.Repeat("-", 80) + "\n")
+	for _, l := range strings.Split(g.Example.Source, "\n") {
+		out.WriteString("// " + l + "\n")
+	}
+	out.WriteString("// " + strings.Repeat("-", 80) + "\n\n")
+
+	fmt.Fprintf(&out, `func Test_%s_%s(t *testing.T) {`+"\n", g.Example.Chapter(), g.Example.Digest)
+	out.WriteString("\t")
+	if !g.Example.IsTranslated() {
+		out.WriteString("// ")
+	}
+	out.WriteString(`es, _ := elasticsearch.NewDefaultClient()` + "\n")
+
+	if !g.Example.IsTranslated() {
+		out.WriteString("\n\tt.Error(`Missing implementation for: ")
+
+		out.WriteString(strings.Split(g.Example.Source, "\n")[0])
+		out.WriteString("`)\n")
+	} else {
+		src, err := g.Example.Translated()
+		if err != nil {
+			return nil, err
+		} else {
+			out.WriteString(src)
+		}
+	}
+
+	out.WriteString("}\n")
+
+	return &out, nil
+}
+
+func (g DocGenerator) Output() (io.Reader, error) {
+	var out bytes.Buffer
+
+	fmt.Fprintf(&out, "// Generated from %s\n//\n", g.Filename)
+
+	out.WriteString("[source, go]\n----\n")
+
+	_, err := out.ReadFrom(g.Source)
+	if err != nil {
+		return nil, err
+	}
+
+	out.WriteString("----\n")
+
+	return &out, nil
+}
diff --git a/internal/build/cmd/generate/commands/genexamples/model.go b/internal/build/cmd/generate/commands/genexamples/model.go
new file mode 100644
index 0000000000..12fb5dcdac
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genexamples/model.go
@@ -0,0 +1,206 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genexamples
+
+import (
+	"bufio"
+	"fmt"
+	"regexp"
+	"sort"
+	"strings"
+)
+
+func init() {
+	sort.Strings(EnabledFiles)
+}
+
+// EnabledFiles contains a list of files where documentation should be generated.
+//
+var EnabledFiles = []string{
+	"aggregations/bucket/datehistogram-aggregation.asciidoc",
+	"aggregations/bucket/filter-aggregation.asciidoc",
+	"aggregations/bucket/terms-aggregation.asciidoc",
+	"aggregations/metrics/valuecount-aggregation.asciidoc",
+	"api-conventions.asciidoc",
+	"cat/indices.asciidoc",
+	"cluster/health.asciidoc",
+	"docs/bulk.asciidoc",
+	"docs/delete-by-query.asciidoc",
+	"docs/delete.asciidoc",
+	"docs/get.asciidoc",
+	"docs/index_.asciidoc",
+	"docs/reindex.asciidoc",
+	"docs/update-by-query.asciidoc",
+	"docs/update.asciidoc",
+	"getting-started.asciidoc",
+	"indices/aliases.asciidoc",
+	"indices/create-index.asciidoc",
+	"indices/delete-index.asciidoc",
+	"indices/get-index.asciidoc",
+	"indices/get-mapping.asciidoc",
+	"indices/put-mapping.asciidoc",
+	"indices/templates.asciidoc",
+	"indices/update-settings.asciidoc",
+	"mapping.asciidoc",
+	"mapping/fields/id-field.asciidoc",
+	"mapping/params/fielddata.asciidoc",
+	"mapping/params/format.asciidoc",
+	"mapping/params/multi-fields.asciidoc",
+	"mapping/types/array.asciidoc",
+	"mapping/types/date.asciidoc",
+	"mapping/types/keyword.asciidoc",
+	"mapping/types/nested.asciidoc",
+	"mapping/types/numeric.asciidoc",
+	"query-dsl.asciidoc",
+	"query-dsl/bool-query.asciidoc",
+	"query-dsl/exists-query.asciidoc",
+	"query-dsl/function-score-query.asciidoc",
+	"query-dsl/match-all-query.asciidoc",
+	"query-dsl/match-phrase-query.asciidoc",
+	"query-dsl/match-query.asciidoc",
+	"query-dsl/multi-match-query.asciidoc",
+	"query-dsl/nested-query.asciidoc",
+	"query-dsl/query-string-query.asciidoc",
+	"query-dsl/query_filter_context.asciidoc",
+	"query-dsl/range-query.asciidoc",
+	"query-dsl/regexp-query.asciidoc",
+	"query-dsl/term-query.asciidoc",
+	"query-dsl/terms-query.asciidoc",
+	"query-dsl/wildcard-query.asciidoc",
+	"search.asciidoc",
+	"search/count.asciidoc",
+	"search/request-body.asciidoc",
+	"search/request/from-size.asciidoc",
+	"search/request/scroll.asciidoc",
+	"search/request/sort.asciidoc",
+	"search/search.asciidoc",
+	"search/suggesters.asciidoc",
+	"setup/install/check-running.asciidoc",
+	"setup/logging-config.asciidoc",
+}
+
+var (
+	reHTTPMethod = regexp.MustCompile(`^HEAD|GET|PUT|DELETE|POST`)
+	reAnnotation = regexp.MustCompile(`^(?P<line>.*)\s*\<\d\>\s*$`)
+	reComment    = regexp.MustCompile(`^#\s?`)
+)
+
+// Example represents the code example in documentation.
+//
+// See: https://github.com/elastic/built-docs/blob/master/raw/en/elasticsearch/reference/master/alternatives_report.json
+//
+type Example struct {
+	SourceLocation struct {
+		File string
+		Line int
+	} `json:"source_location"`
+
+	Digest string
+	Source string
+}
+
+// IsEnabled returns true when the example should be processed.
+//
+func (e Example) IsEnabled() bool {
+	// TODO(karmi): Use "filepatch.Match()" to support glob patterns
+
+	index := sort.SearchStrings(EnabledFiles, e.SourceLocation.File)
+
+	if index > len(EnabledFiles)-1 || EnabledFiles[index] != e.SourceLocation.File {
+		return false
+	}
+
+	return true
+}
+
+// IsExecutable returns true when the example contains a request.
+//
+func (e Example) IsExecutable() bool {
+	return reHTTPMethod.MatchString(e.Source)
+}
+
+// IsTranslated returns true when the example can be converted to Go source code.
+//
+func (e Example) IsTranslated() bool {
+	return Translator{Example: e}.IsTranslated()
+}
+
+// ID returns example identifier.
+//
+func (e Example) ID() string {
+	return fmt.Sprintf("%s:%d", e.SourceLocation.File, e.SourceLocation.Line)
+}
+
+// Chapter returns the example chapter.
+//
+func (e Example) Chapter() string {
+	r := strings.NewReplacer("/", "_", "-", "_", ".asciidoc", "")
+	return r.Replace(e.SourceLocation.File)
+}
+
+// GithubURL returns a link for the example source.
+//
+func (e Example) GithubURL() string {
+	return fmt.Sprintf("https://github.com/elastic/elasticsearch/blob/master/docs/reference/%s#L%d", e.SourceLocation.File, e.SourceLocation.Line)
+}
+
+// Commands returns the list of commands from source.
+//
+func (e Example) Commands() ([]string, error) {
+	var (
+		buf  strings.Builder
+		list []string
+		scan = bufio.NewScanner(strings.NewReader(e.Source))
+	)
+
+	for scan.Scan() {
+		line := scan.Text()
+
+		if reComment.MatchString(line) {
+			continue
+		}
+
+		line = reAnnotation.ReplaceAllString(line, "$1")
+
+		if reHTTPMethod.MatchString(line) {
+			if buf.Len() > 0 {
+				list = append(list, buf.String())
+			}
+			buf.Reset()
+		}
+
+		buf.WriteString(line)
+		buf.WriteString("\n")
+	}
+
+	if err := scan.Err(); err != nil {
+		return list, err
+	}
+
+	if buf.Len() > 0 {
+		list = append(list, buf.String())
+	}
+
+	return list, nil
+}
+
+// Translated returns the code translated from Console to Go.
+//
+func (e Example) Translated() (string, error) {
+	return Translator{Example: e}.Translate()
+}
diff --git a/internal/build/cmd/generate/commands/genexamples/skips.go b/internal/build/cmd/generate/commands/genexamples/skips.go
new file mode 100644
index 0000000000..1ee6928179
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genexamples/skips.go
@@ -0,0 +1,22 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genexamples
+
+var skipPatterns = []string{
+	`size=surprise_me`, // Size must be numeric
+}
diff --git a/internal/build/cmd/generate/commands/genexamples/translator.go b/internal/build/cmd/generate/commands/genexamples/translator.go
new file mode 100644
index 0000000000..7337a8bbe9
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genexamples/translator.go
@@ -0,0 +1,1692 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genexamples
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log"
+	"net/url"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+)
+
+const testCheck = "\t" + `if err != nil {            // SKIP
+		t.Fatalf("Error getting the response: %s", err)	 // SKIP
+	}                                                  // SKIP
+	defer res.Body.Close()                             // SKIP
+`
+
+var _ = log.Print
+
+// ConsoleToGo contains translation rules.
+//
+var ConsoleToGo = []TranslateRule{
+
+	{ // ----- Info() -----------------------------------------------------------
+		Pattern: `^GET /\s*$`,
+		Func: func(in string) (string, error) {
+			return "res, err := es.Info()", nil
+		}},
+
+	{ // ----- Cat.Health() -----------------------------------------------------
+		Pattern: `^GET /?_cat/health\?v`,
+		Func: func(in string) (string, error) {
+			return "\tres, err := es.Cat.Health(es.Cat.Health.WithV(true))", nil
+		}},
+
+	{ // ----- Cat.Indices() -----------------------------------------------------
+		Pattern: `^GET /?_cat/indices`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?_cat/indices/?(?P<index>[^/\s\?]+)?(?P<params>\??[\S]+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			fmt.Fprint(&src, "\tres, err := es.Cat.Indices(\n")
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\tes.Cat.Indices.WithIndex([]string{%q}...),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Cat.Indices", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Cluster.Health() -----------------------------------------------------
+		Pattern: `^GET /?_cluster/health`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(?P<method>GET) /?_cluster/health/?(?P<index>[^/\s\?]+)?(?P<params>\??[\S]+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			fmt.Fprint(&src, "\tres, err := es.Cluster.Health(\n")
+
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\tes.Cluster.Health.WithIndex([]string{%q}...),\n", matches[2])
+			}
+
+			if matches[3] != "" {
+				params, err := queryToParams(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Cluster.Health", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Cluster.State() -----------------------------------------------------
+		Pattern: `^GET /?_cluster/state`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(?P<method>GET) /?_cluster/state/?(?P<index>[^/\s\?]+)?(?P<params>\??[\S]+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			fmt.Fprint(&src, "\tres, err := es.Cluster.State(\n")
+
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\tes.Cluster.State.WithIndex([]string{%q}...),\n", matches[2])
+			}
+
+			if matches[3] != "" {
+				params, err := queryToParams(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Cluster.State", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Cluster.PutSettings() --------------------------------------------
+		Pattern: `^PUT /?_cluster/settings`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(?P<method>PUT) /?_cluster/settings/?(?P<params>\??[\S]+)?\s?(?P<body>.*)`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			fmt.Fprint(&src, "\tres, err := es.Cluster.PutSettings(\n")
+			body, err := bodyStringToReader(matches[3])
+			if err != nil {
+				return "", fmt.Errorf("error converting body: %s", err)
+			}
+			fmt.Fprintf(&src, "\t%s", body)
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Cluster.PutSettings", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+
+		}},
+
+	{ // ----- Nodes.Stats() -----------------------------------------------------
+		Pattern: `^GET /?_nodes/.*/?stats`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(?P<method>GET) /?_nodes/(?P<node_id>[[:alnum:]]+)?/?stats/?(?P<metric>[^/\s\?]+)?/?(?P<index_metric>[^/\s?]+)?(?P<params>\??[\S]+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+			fmt.Println("matches")
+			for i, m := range matches {
+				fmt.Println(i, ":", m)
+			}
+			fmt.Fprint(&src, "\tres, err := es.Nodes.Stats(\n")
+
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\tes.Nodes.Stats.WithNodeID([]string{%q}...),\n", matches[2])
+			}
+
+			if matches[3] != "" {
+				fmt.Fprintf(&src, "\tes.Nodes.Stats.WithMetric([]string{%q}...),\n", matches[3])
+			}
+
+			if matches[4] != "" {
+				fmt.Fprintf(&src, "\tes.Nodes.Stats.WithIndexMetric([]string{%q}...),\n", matches[4])
+			}
+
+			if matches[5] != "" {
+				params, err := queryToParams(matches[5])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Nodes.Stats", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- UpdateByQueryRethrottle() ---------------------------------------------------------
+		Pattern: `^POST /?_update_by_query.+_rethrottle`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?_update_by_query/(?P<task_id>\S+)/_rethrottle(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.UpdateByQueryRethrottle(\n")
+			fmt.Fprintf(&src, "%q,\n", matches[1])
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				var requestsPerSecond []string
+				for key, value := range params {
+					if key == "requests_per_second" {
+						requestsPerSecond = value
+						delete(params, key)
+					}
+				}
+				fmt.Fprintf(&src, "esapi.IntPtr(%v),\n", strings.Join(requestsPerSecond, ""))
+
+				args, err := paramsToArguments("UpdateByQueryRethrottle", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- UpdateByQuery() ---------------------------------------------------------
+		Pattern: `^(GET|POST) /?(\S+)?/?_update_by_query`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(GET|POST) /?(?P<index>[^/]*)?/?_update_by_query(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.UpdateByQuery(\n")
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\t[]string{%q},\n", matches[2])
+			}
+
+			if strings.TrimSpace(matches[4]) != "" {
+				body, err := bodyStringToReader(matches[4])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\tes.UpdateByQuery.WithBody(%s),\n", body)
+			}
+
+			var params url.Values
+			if matches[3] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[3], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("UpdateByQuery", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- PutIngestPipeline() ------------------------------------------------------
+		Pattern: `^PUT /?_ingest/pipeline.*`,
+		Func: func(in string) (string, error) {
+			var (
+				src strings.Builder
+			)
+
+			re := regexp.MustCompile(`(?ms)^PUT /?_ingest/pipeline/(?P<id>[^/\?\s]+)/?(?P<params>\??[\S]+)?\s?(?P<body>.*)`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Ingest.PutPipeline(\n")
+			fmt.Fprintf(&src, "\t%q,\n", matches[1])
+
+			if matches[3] != "" {
+				body, err := bodyStringToReader(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\t%s,\n", body)
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Ingest.PutPipeline", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, "\t%s", args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		},
+	},
+
+	{ // ----- Index() or Create() ----------------------------------------------
+		Pattern: `^(PUT|POST) /?.+/(_doc|_create|_update)/?.*`,
+		Func: func(in string) (string, error) {
+			var (
+				src     strings.Builder
+				apiName string
+			)
+
+			re := regexp.MustCompile(`(?ms)^(?P<method>PUT|POST) /?(?P<index>.+)/(?P<api>_doc|_create|_update)/?(?P<id>\w+)?(?P<params>\??[\S]+)?\s?(?P<body>.*)`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			switch matches[3] {
+			case "_doc":
+				apiName = "Index"
+			case "_create":
+				apiName = "Create"
+			case "_update":
+				apiName = "Update"
+			default:
+				return "", fmt.Errorf("Unknown API [%s]", matches[3])
+			}
+
+			src.WriteString("\tres, err := es." + apiName + "(\n")
+
+			fmt.Fprintf(&src, "\t%q,\n", matches[2])
+
+			if apiName == "Create" || apiName == "Update" {
+				fmt.Fprintf(&src, "\t%q,\n", matches[4])
+			}
+
+			body, err := bodyStringToReader(matches[6])
+			if err != nil {
+				return "", fmt.Errorf("error converting body: %s", err)
+			}
+			fmt.Fprintf(&src, "\t%s,\n", body)
+
+			if apiName == "Index" {
+				if matches[4] != "" {
+					fmt.Fprintf(&src, "\tes."+apiName+".WithDocumentID(%q),\n", matches[4])
+				}
+			}
+
+			if matches[5] != "" {
+				params, err := queryToParams(matches[5])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments(apiName, params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\tes." + apiName + ".WithPretty(),\n")
+			src.WriteString("\t)")
+
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.GetMapping() -------------------------------------------------
+		Pattern: `^GET /?.*_mapping`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>[^/\s]+)?(?P<params>\??[\S/]+)?_mapping\s?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.GetMapping(")
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\tes.Indices.GetMapping.WithIndex(%q),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.PutTemplate", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.PutMapping() -------------------------------------------------
+		Pattern: `^PUT /?[^/\s]+/_mapping`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^PUT /?(?P<index>[^/\s]+)(?P<params>\??[\S/]+)?_mapping\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.PutMapping(")
+
+			if matches[2] != "" || matches[3] != "" {
+				fmt.Fprintf(&src, "\n\t[]string{%q},\n", matches[1])
+
+				if matches[3] != "" {
+					body, err := bodyStringToReader(matches[3])
+					if err != nil {
+						return "", fmt.Errorf("error converting body: %s", err)
+					}
+					fmt.Fprintf(&src, "\t%s,\n", body)
+				}
+
+				if matches[2] != "" {
+					params, err := queryToParams(matches[2])
+					if err != nil {
+						return "", fmt.Errorf("error parsing URL params: %s", err)
+					}
+					args, err := paramsToArguments("Indices.PutMapping", params)
+					if err != nil {
+						return "", fmt.Errorf("error converting params to arguments: %s", err)
+					}
+					fmt.Fprintf(&src, "\t%s", args)
+				}
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.GetSettings() -------------------------------------------------
+		Pattern: `^GET /?[^/\s]+/_settings`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>[^/\s]+)/_settings(?P<params>\??[\S/]+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.GetSettings(")
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\n\t\tes.Indices.GetSettings.WithIndex([]string{%q}...),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.GetSettings", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, "\t\t%s", args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.PutSettings() -------------------------------------------------
+		Pattern: `^PUT /?[^/\s]+/_settings`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^PUT /?(?P<index>[^/\s]+)(?P<params>\??[\S/]+)?_settings\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.PutSettings(")
+
+			if matches[2] != "" || matches[3] != "" {
+				if matches[3] != "" {
+					body, err := bodyStringToReader(matches[3])
+					if err != nil {
+						return "", fmt.Errorf("error converting body: %s", err)
+					}
+					fmt.Fprintf(&src, "\t%s,\n", body)
+				}
+
+				if matches[1] != "" {
+					fmt.Fprintf(&src, "\n\tes.Indices.PutSettings.WithIndex([]string{%q}...),\n", matches[1])
+				}
+
+				if matches[2] != "" {
+					params, err := queryToParams(matches[2])
+					if err != nil {
+						return "", fmt.Errorf("error parsing URL params: %s", err)
+					}
+					args, err := paramsToArguments("Indices.PutSettings", params)
+					if err != nil {
+						return "", fmt.Errorf("error converting params to arguments: %s", err)
+					}
+					fmt.Fprintf(&src, "\t%s", args)
+				}
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.PutTemplate() -------------------------------------------------
+		Pattern: `^PUT /?_template/[^/\s]+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^PUT /?_template/(?P<name>[^/\s]+)/?(?P<params>\??[\S/]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.PutTemplate(")
+			fmt.Fprintf(&src, "\n\t%q,\n", matches[1])
+
+			if matches[2] != "" || matches[3] != "" {
+				if strings.TrimSpace(matches[3]) != "" {
+					body, err := bodyStringToReader(matches[3])
+					if err != nil {
+						return "", fmt.Errorf("error converting body: %s", err)
+					}
+					fmt.Fprintf(&src, "\t%s,\n", body)
+				}
+
+				if matches[2] != "" {
+					params, err := queryToParams(matches[2])
+					if err != nil {
+						return "", fmt.Errorf("error parsing URL params: %s", err)
+					}
+					args, err := paramsToArguments("Indices.PutTemplate", params)
+					if err != nil {
+						return "", fmt.Errorf("error converting params to arguments: %s", err)
+					}
+					fmt.Fprintf(&src, args)
+				}
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.GetTemplate() -------------------------------------------------
+		Pattern: `^GET /?_template/[^/\s]+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?_template/(?P<name>[^/\?\s]+)/?(?P<params>\??[\S/]+)?\s?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.GetTemplate(")
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\n\tes.Indices.GetTemplate.WithName(%q),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.GetTemplate", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Create() -------------------------------------------------
+		Pattern: `^PUT /?[^/\s]+\s?`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^PUT /?(?P<index>[^/\s]+)(?P<params>\??[\S/]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.Create(")
+			if matches[2] != "" || matches[3] != "" {
+				fmt.Fprintf(&src, "\n\t%q,\n", matches[1])
+
+				if strings.TrimSpace(matches[3]) != "" {
+					body, err := bodyStringToReader(matches[3])
+					if err != nil {
+						return "", fmt.Errorf("error converting body: %s", err)
+					}
+					fmt.Fprintf(&src, "\tes.Indices.Create.WithBody(%s),\n", body)
+				}
+
+				if matches[2] != "" {
+					params, err := queryToParams(matches[2])
+					if err != nil {
+						return "", fmt.Errorf("error parsing URL params: %s", err)
+					}
+					args, err := paramsToArguments("Indices.Create", params)
+					if err != nil {
+						return "", fmt.Errorf("error converting params to arguments: %s", err)
+					}
+					fmt.Fprintf(&src, args)
+				}
+			} else {
+				fmt.Fprintf(&src, "%q", matches[1])
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- ClearScroll() ---------------------------------------------------------
+		Pattern: `^DELETE /?_search/scroll`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^DELETE /?_search/scroll/?(?P<ids>[[:alnum:]=_,]*)?(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.ClearScroll(\n")
+
+			if strings.TrimSpace(matches[1]) != "" {
+				src.WriteString("\t\tes.ClearScroll.WithScrollID(")
+				scrollIDs := strings.Split(matches[1], ",")
+				for i, s := range scrollIDs {
+					fmt.Fprintf(&src, "%q", s)
+					if i < len(scrollIDs)-1 {
+						src.WriteString(",")
+					}
+				}
+				src.WriteString("),\n")
+			}
+
+			if strings.TrimSpace(matches[3]) != "" {
+				body, err := bodyStringToReader(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\t\tes.ClearScroll.WithBody(%s),\n", body)
+			}
+
+			var params url.Values
+			if matches[2] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("ClearScroll", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Delete() ---------------------------------------------------------
+		Pattern: `^DELETE /?\w+/_doc/\w+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^DELETE /?(?P<index>\w+)/_doc/(?P<id>\w+)(?P<params>\??\S+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			fmt.Fprint(&src, "\tres, err := es.Delete(")
+
+			if matches[3] != "" {
+				fmt.Fprintf(&src, "\t%q,\n\t%q,\n", matches[1], matches[2])
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[3], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Delete", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+
+				src.WriteString("\tes.Delete.WithPretty(),\n")
+			} else {
+				fmt.Fprintf(&src, "\t%q, %q, es.Delete.WithPretty()", matches[1], matches[2])
+			}
+			src.WriteString(")")
+
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Delete() -------------------------------------------------
+		Pattern: `^DELETE /?[^/\s]+[^_/]*`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^DELETE /?(?P<index>[^/\s]+)(?P<params>\??[\S/]+)?$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.Delete(")
+
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\n\t[]string{%q},\n", matches[1])
+
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.Delete", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			} else {
+				fmt.Fprintf(&src, "[]string{%q}", matches[1])
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Refresh() -------------------------------------------------
+		Pattern: `^GET /?[^/\s]*/?_refresh`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>[^/\s]*)/?_refresh$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.Refresh(")
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "[]string{%q}", matches[1])
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Open() + Indices.Close() ---------------------------------
+		Pattern: `^POST /?[^/\s]*/?(?P<operation>_close|_open)\s*`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+			var apiName string
+
+			re := regexp.MustCompile(`(?ms)^POST /?(?P<index>[^/\s]*)/?(?P<operation>_open|_close)\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			switch matches[2] {
+			case "_open":
+				apiName = "Open"
+			case "_close":
+				apiName = "Close"
+			default:
+				return "", fmt.Errorf("unknown operation [%s]", matches[2])
+			}
+
+			fmt.Fprintf(&src, "\tres, err := es.Indices.%s(", apiName)
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "[]string{%q}", matches[1])
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Aliases() + Indices.PutAlias() ---------------------------
+		Pattern: `^POST /?[^/\s]*/?_aliases`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+			var apiName string
+
+			re := regexp.MustCompile(`(?ms)^POST /?(?P<index>[^/\s]*)/?_aliases/?(?P<params>\??[\S/]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			if matches[1] != "" {
+				apiName = "PutAlias"
+				src.WriteString("\tres, err := es.Indices.PutAlias(")
+				fmt.Fprintf(&src, "[]string{%q}", matches[1])
+			} else {
+				apiName = "UpdateAliases"
+				src.WriteString("\tres, err := es.Indices.UpdateAliases(")
+			}
+
+			if strings.TrimSpace(matches[3]) != "" {
+				body, err := bodyStringToReader(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				if apiName == "PutAlias" {
+					fmt.Fprintf(&src, "\tes.Indices.%s.WithBody(%s),\n", apiName, body)
+				} else {
+					fmt.Fprintf(&src, "\t%s,\n", body)
+				}
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments(apiName, params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Forcemerge() -------------------------------------------------
+		Pattern: `^POST /?[^/\s]*/?_forcemerge`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?(?P<index>[^/\s]*)/?_forcemerge/?(?P<params>\??[\S/]+)?$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.Forcemerge(")
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\tes.Indices.Forcemerge.WithIndex([]string{%q}...),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.Forcemerge", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+
+	{ // ----- Get() or GetSource() ---------------------------------------------
+		Pattern: `^GET /?.+/(_doc|_source)/\w+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>.+)/(?P<api>_doc|_source)/(?P<id>\w+)(?P<params>\??\S+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			var apiName string
+			switch matches[2] {
+			case "_doc":
+				apiName = "Get"
+			case "_source":
+				apiName = "GetSource"
+			default:
+				return "", fmt.Errorf("unknown API variant %q", matches[2])
+			}
+
+			if matches[4] == "" {
+				fmt.Fprintf(&src, "\tres, err := es."+apiName+"(%q, %q, es."+apiName+".WithPretty()", matches[1], matches[3])
+			} else {
+				fmt.Fprintf(&src, "\tres, err := es."+apiName+"(\n\t%q,\n\t%q,\n\t", matches[1], matches[3])
+
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[4], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments(apiName, params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+
+				src.WriteString("\tes." + apiName + ".WithPretty(),\n")
+			}
+
+			src.WriteString(")")
+
+			return src.String(), nil
+		}},
+
+	{ // ----- Exists() or ExistsSource() ---------------------------------------
+		Pattern: `^HEAD /?\w+/(_doc|_source)/\w+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^HEAD /?(?P<index>\w+)/(?P<api>_doc|_source)/(?P<id>\w+)(?P<params>\??[\S]+)?\s*$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			var apiName string
+			switch matches[2] {
+			case "_doc":
+				apiName = "Exists"
+			case "_source":
+				apiName = "ExistsSource"
+			default:
+				return "", fmt.Errorf("unknown API variant %q", matches[2])
+			}
+
+			if matches[4] == "" {
+				fmt.Fprintf(&src, "\tres, err := es."+apiName+"(%q, %q, es."+apiName+".WithPretty()", matches[1], matches[2])
+			} else {
+				fmt.Fprintf(&src, "\tres, err := es."+apiName+"(\n\t%q,\n\t%q,\n\t", matches[1], matches[2])
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[4], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments(apiName, params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+
+				src.WriteString("\tes." + apiName + ".WithPretty(),\n")
+			}
+
+			src.WriteString(")")
+
+			return src.String(), nil
+		}},
+
+	{ // ----- Scroll() ---------------------------------------------------------
+		Pattern: `^(GET|POST) /?_search/scroll`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(GET|POST) /?_search/scroll(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Scroll(\n")
+
+			if strings.TrimSpace(matches[3]) != "" {
+				body, err := bodyStringToReader(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\tes.Scroll.WithBody(%s),\n", body)
+			}
+
+			var params url.Values
+			if matches[2] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Search", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			var hasPretty bool
+			for k, _ := range params {
+				if k == "pretty" {
+					hasPretty = true
+				}
+			}
+
+			if !hasPretty {
+				src.WriteString("\tes.Scroll.WithPretty(),\n")
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Search() ---------------------------------------------------------
+		Pattern: `^(GET|POST) /?[^/]*/?_search`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(GET|POST) /?(?P<index>[^/]*)?/?_search(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Search(\n")
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\tes.Search.WithIndex(%q),\n", matches[2])
+			}
+
+			if strings.TrimSpace(matches[4]) != "" {
+				body, err := bodyStringToReader(matches[4])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\tes.Search.WithBody(%s),\n", body)
+			}
+
+			var params url.Values
+			if matches[3] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[3], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Search", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			var hasPretty bool
+			for k, _ := range params {
+				if k == "pretty" {
+					hasPretty = true
+				}
+			}
+
+			if !hasPretty {
+				src.WriteString("\tes.Search.WithPretty(),\n")
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Count() ---------------------------------------------------------
+		Pattern: `^GET /?[^/]*/?_count`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>[^/]*)?/?_count(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Count(\n")
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\tes.Count.WithIndex(%q),\n", matches[2])
+			}
+
+			if strings.TrimSpace(matches[3]) != "" {
+				body, err := bodyStringToReader(matches[3])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\tes.Count.WithBody(%s),\n", body)
+			}
+
+			var params url.Values
+			if matches[2] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Count", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			var hasPretty bool
+			for k, _ := range params {
+				if k == "pretty" {
+					hasPretty = true
+				}
+			}
+
+			if !hasPretty {
+				src.WriteString("\tes.Count.WithPretty(),\n")
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- DeleteByQueryRethrottle() ---------------------------------------------------------
+		Pattern: `^POST /?_delete_by_query.+_rethrottle`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?_delete_by_query/(?P<task_id>\S+)/_rethrottle(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.DeleteByQueryRethrottle(\n")
+			fmt.Fprintf(&src, "%q,\n", matches[1])
+
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				var requestsPerSecond []string
+				for key, value := range params {
+					if key == "requests_per_second" {
+						requestsPerSecond = value
+						delete(params, key)
+					}
+				}
+				fmt.Fprintf(&src, "esapi.IntPtr(%v),\n", strings.Join(requestsPerSecond, ""))
+
+				args, err := paramsToArguments("DeleteByQueryRethrottle", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- DeleteByQuery() ---------------------------------------------------------
+		Pattern: `^(GET|POST) /?(\S+)?/?_delete_by_query`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^(GET|POST) /?(?P<index>[^/]*)?/?_delete_by_query(?P<params>\??[\S]+)?\s?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.DeleteByQuery(\n")
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\t[]string{%q},\n", matches[2])
+			}
+
+			if strings.TrimSpace(matches[4]) != "" {
+				body, err := bodyStringToReader(matches[4])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprintf(&src, "\t%s,\n", body)
+			}
+
+			var params url.Values
+			if matches[3] != "" {
+				var err error
+				params, err = url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[3], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("DeleteByQuery", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- ReindexRethrottle() ---------------------------------------------------------
+		Pattern: `^POST /?_reindex.+_rethrottle`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?_reindex/(?P<task_id>\S+)/_rethrottle(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.ReindexRethrottle(\n")
+			fmt.Fprintf(&src, "%q,\n", matches[1])
+
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				var requestsPerSecond []string
+				for key, value := range params {
+					if key == "requests_per_second" {
+						requestsPerSecond = value
+						delete(params, key)
+					}
+				}
+				fmt.Fprintf(&src, "esapi.IntPtr(%v),\n", strings.Join(requestsPerSecond, ""))
+
+				args, err := paramsToArguments("ReindexRethrottle", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Reindex() ---------------------------------------------------------
+		Pattern: `^POST /?_reindex`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?_reindex(?P<params>\??[\S/]+)?\s?(?P<body>.+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Reindex(\n")
+
+			if strings.TrimSpace(matches[2]) != "" {
+				body, err := bodyStringToReader(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error converting body: %s", err)
+				}
+				fmt.Fprint(&src, body)
+			}
+
+			if matches[1] != "" {
+				src.WriteString(",\n")
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[1], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Reindex", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Bulk() ---------------------------------------------------------
+		Pattern: `^POST /?(\S+)?/?_bulk`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?(?P<index>\S+)?/?_bulk(?P<params>\??[\S/]+)?\s?\n?(?P<body>.+)?`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Bulk(\n")
+
+			if matches[3] != "" {
+				fmt.Fprintf(&src, "\tstrings.NewReader(`\n%s`),\n", matches[3])
+			}
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\tes.Bulk.WithIndex(%q),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Bulk", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprint(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Tasks.Get() ------------------------------------------------------------
+		Pattern: `^GET /?_tasks/.+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?_tasks/?(?P<task_id>\S+)?/?(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Tasks.Get(\n")
+
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "\t%q,\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				args, err := paramsToArguments("Tasks.Get", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Tasks.List() ------------------------------------------------------------
+		Pattern: `^GET /?_tasks`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?_tasks/?(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Tasks.List(\n")
+
+			if matches[1] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[1], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				args, err := paramsToArguments("Tasks.List", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Tasks.Cancel() ---------------------------------------------------------
+		Pattern: `^POST /?_tasks.+_cancel`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^POST /?_tasks/(?P<task_id>\S+)/_cancel(?P<params>\??[\S/]+)?`)
+
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Tasks.Cancel(\n")
+			if matches[1] != "" {
+				fmt.Fprintf(&src, "es.Tasks.Cancel.WithTaskID(%q),\n", matches[1])
+			}
+
+			if matches[2] != "" {
+				params, err := url.ParseQuery(strings.TrimPrefix(strings.TrimPrefix(matches[2], "/"), "?"))
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+
+				args, err := paramsToArguments("Tasks.Cancel", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			}
+
+			src.WriteString("\t)")
+			return src.String(), nil
+		}},
+
+	{ // ----- Indices.Get() -------------------------------------------------
+		Pattern: `^GET /?[^/_\s]+`,
+		Func: func(in string) (string, error) {
+			var src strings.Builder
+
+			re := regexp.MustCompile(`(?ms)^GET /?(?P<index>[^/\s]+)(?P<params>\??[\S/]+)?$`)
+			matches := re.FindStringSubmatch(in)
+			if matches == nil {
+				return "", errors.New("cannot match example source to pattern")
+			}
+
+			src.WriteString("\tres, err := es.Indices.Get(")
+
+			if matches[2] != "" {
+				fmt.Fprintf(&src, "\n\t[]string{%q},\n", matches[1])
+
+				params, err := queryToParams(matches[2])
+				if err != nil {
+					return "", fmt.Errorf("error parsing URL params: %s", err)
+				}
+				args, err := paramsToArguments("Indices.Get", params)
+				if err != nil {
+					return "", fmt.Errorf("error converting params to arguments: %s", err)
+				}
+				fmt.Fprintf(&src, args)
+			} else {
+				fmt.Fprintf(&src, "[]string{%q}", matches[1])
+			}
+
+			src.WriteString(")")
+			return src.String(), nil
+		}},
+}
+
+// Translator represents converter from Console source code to Go source code.
+//
+type Translator struct {
+	Example Example
+}
+
+// TranslateRule represents a rule for translating code from Console to Go.
+//
+type TranslateRule struct {
+	Pattern string
+	Func    func(string) (string, error)
+}
+
+// IsTranslated returns true when a rule for translating the Console example to Go source code exists.
+//
+func (t Translator) IsTranslated() bool {
+	var translated bool
+
+	cmds, err := t.Example.Commands()
+	if err != nil {
+		panic(fmt.Sprintf("error getting example commands: %s", err))
+	}
+
+	for _, c := range cmds {
+		for _, r := range ConsoleToGo {
+			if r.Match(c) {
+				translated = true
+			}
+		}
+	}
+
+	return translated
+}
+
+// Translate returns the Console code translated to Go.
+//
+func (t Translator) Translate() (string, error) {
+	var out strings.Builder
+
+	cmds, err := t.Example.Commands()
+	if err != nil {
+		return "", fmt.Errorf("error getting example commands: %s", err)
+	}
+
+	out.WriteRune('\n')
+	fmt.Fprintf(&out, "\t// tag:%s[]\n", t.Example.Digest)
+	for i, c := range cmds {
+		var translated bool
+		for _, r := range ConsoleToGo {
+			if translated {
+				break
+			}
+
+			if r.Match(c) {
+				src, err := r.Func(c)
+				if err != nil {
+					return "", fmt.Errorf("error translating the example: %s", err)
+				}
+				translated = true
+
+				if len(cmds) > 1 {
+					out.WriteString("\t{\n")
+				}
+				out.WriteString(src)
+				out.WriteRune('\n')
+				out.WriteString("\tfmt.Println(res, err)\n")
+				out.WriteString(testCheck)
+				if len(cmds) > 1 {
+					out.WriteString("\t}\n")
+					if i != len(cmds)-1 {
+						out.WriteString("\n")
+					}
+				}
+			}
+		}
+		if !translated {
+			return "", errors.New("no rule to translate the example")
+		}
+	}
+	fmt.Fprintf(&out, "\t// end:%s[]\n", t.Example.Digest)
+	return out.String(), nil
+}
+
+// Match returns true when the input matches the rule pattern.
+//
+func (r TranslateRule) Match(input string) bool {
+	matched, _ := regexp.MatchString(r.Pattern, input)
+	return matched
+}
+
+// queryToParams extracts the URL params.
+//
+func queryToParams(input string) (url.Values, error) {
+	input = strings.TrimPrefix(input, "/")
+	input = strings.TrimPrefix(input, "?")
+	return url.ParseQuery(input)
+}
+
+// paramsToArguments converts params to API arguments.
+//
+func paramsToArguments(api string, params url.Values) (string, error) {
+	var b strings.Builder
+
+	keys := make([]string, 0, len(params))
+	for k := range params {
+		keys = append(keys, k)
+	}
+
+	sort.Strings(keys)
+	for _, k := range keys {
+		var (
+			name  string
+			value string
+		)
+
+		value = strings.Join(params[k], ",")
+
+		switch k {
+		case "q":
+			name = "Query"
+		default:
+			name = utils.NameToGo(k)
+		}
+
+		switch k {
+		case "timeout", "scroll": // duration
+			if params[k][0] == "" {
+				break
+			}
+			dur, err := time.ParseDuration(params[k][0])
+			if err != nil {
+				return "", fmt.Errorf("error parsing duration [%s]: %s", params[k][0], err)
+			}
+			value = fmt.Sprintf("time.Duration(%d)", time.Duration(dur))
+		case "from", "size", "terminate_after", "version", "requests_per_second", "scroll_size", "max_num_segments": // numeric
+			value = fmt.Sprintf("%s", value)
+		case "pretty", "error_trace":
+			value = "" // Helper methods don't take any value
+		case "refresh":
+			switch api {
+			case "Index":
+				if params[k][0] == "" {
+					value = `"true"` // WithRefresh() needs a string
+				} else {
+					value = strconv.Quote(value)
+				}
+			case "Reindex", "DeleteByQuery", "UpdateByQuery":
+				if params[k][0] == "" {
+					value = "true" // WithRefresh() needs a boolean
+				}
+			default:
+				value = strconv.Quote(value)
+			}
+		case "detailed", "flat_settings": // bool
+			value = string(value)
+		case "v": // Blank bool
+			value = "true"
+		default:
+			value = strconv.Quote(value)
+		}
+		fmt.Fprintf(&b, "\tes.%s.With%s(%s),\n", api, name, value)
+	}
+
+	return b.String(), nil
+}
+
+// bodyStringToReader reformats input JSON string and returns it wrapped in strings.NewReader.
+//
+func bodyStringToReader(input string) (string, error) {
+	var body bytes.Buffer
+	err := json.Indent(&body, []byte(input), "\t\t", "  ")
+	if err != nil {
+		fmt.Printf("Input: %q", input)
+		return "", err
+	}
+	return fmt.Sprintf("strings.NewReader(`%s`)", strings.TrimRight(body.String(), "\n")), nil
+}
diff --git a/internal/cmd/generate/commands/gensource/command.go b/internal/build/cmd/generate/commands/gensource/command.go
old mode 100755
new mode 100644
similarity index 59%
rename from internal/cmd/generate/commands/gensource/command.go
rename to internal/build/cmd/generate/commands/gensource/command.go
index 569118833b..0665427784
--- a/internal/cmd/generate/commands/gensource/command.go
+++ b/internal/build/cmd/generate/commands/gensource/command.go
@@ -1,20 +1,35 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gensource
 
 import (
 	"bytes"
 	"fmt"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
 	"io"
 	"os"
 	"path/filepath"
 	"strings"
 	"time"
 
-	"golang.org/x/tools/imports"
-
 	"github.com/spf13/cobra"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/commands"
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 var (
@@ -24,8 +39,6 @@ var (
 	color  *bool
 	debug  *bool
 	info   *bool
-
-	skipAPIRegistry *bool
 )
 
 var (
@@ -38,7 +51,6 @@ func init() {
 	input = gensourceCmd.Flags().StringP("input", "i", "", "Path to a folder or files with Elasticsearch REST API specification")
 	output = gensourceCmd.Flags().StringP("output", "o", "", "Path to a folder for generated output")
 	gofmt = gensourceCmd.Flags().BoolP("gofmt", "f", true, "Format generated output with 'gofmt'")
-	skipAPIRegistry = gensourceCmd.Flags().BoolP("skip-registry", "s", false, "Skip generating the API registry (api._.go)")
 	color = gensourceCmd.Flags().BoolP("color", "c", true, "Syntax highlight the debug output")
 	debug = gensourceCmd.Flags().BoolP("debug", "d", false, "Print the generated source to terminal")
 	info = gensourceCmd.Flags().Bool("info", false, "Print the API details to terminal")
@@ -47,21 +59,20 @@ func init() {
 	gensourceCmd.MarkFlagRequired("output")
 	gensourceCmd.Flags().SortFlags = false
 
-	commands.RegisterCmd(gensourceCmd)
+	cmd.RegisterCmd(gensourceCmd)
 }
 
 var gensourceCmd = &cobra.Command{
-	Use:   "source",
-	Short: "Generate Go API from Elasticsearch REST API spec",
+	Use:   "apisource",
+	Short: "Generate the Go APIs from the Elasticsearch REST API specification",
 	Run: func(cmd *cobra.Command, args []string) {
 		command := &Command{
-			Input:           *input,
-			Output:          *output,
-			Gofmt:           *gofmt,
-			DebugInfo:       *info,
-			DebugSource:     *debug,
-			ColorizeSource:  *color,
-			SkipAPIRegistry: *skipAPIRegistry,
+			Input:          *input,
+			Output:         *output,
+			Gofmt:          *gofmt,
+			DebugInfo:      *info,
+			DebugSource:    *debug,
+			ColorizeSource: *color,
 		}
 		err := command.Execute()
 		if err != nil {
@@ -74,13 +85,12 @@ var gensourceCmd = &cobra.Command{
 // Command represents the "gensource" command.
 //
 type Command struct {
-	Input           string
-	Output          string
-	Gofmt           bool
-	DebugInfo       bool
-	DebugSource     bool
-	ColorizeSource  bool
-	SkipAPIRegistry bool
+	Input          string
+	Output         string
+	Gofmt          bool
+	DebugInfo      bool
+	DebugSource    bool
+	ColorizeSource bool
 }
 
 // Execute runs the command.
@@ -145,7 +155,6 @@ func (cmd *Command) Execute() (err error) {
 		if err != nil {
 			return err
 		}
-		defer f.Close()
 
 		if err := cmd.processFile(f); err != nil {
 			return fmt.Errorf("Processing file %q: %s", fname, err)
@@ -156,16 +165,12 @@ func (cmd *Command) Execute() (err error) {
 		if err != nil {
 			return fmt.Errorf("error creating endpoint for %q: %s", fname, err)
 		}
+		f.Close()
+
 		endpoints = append(endpoints, e)
 		stats.n++
 	}
 
-	if cmd.Output != "-" && !cmd.SkipAPIRegistry {
-		if err := cmd.processAPIConstructor(endpoints); err != nil {
-			return fmt.Errorf("error handling API constructor: %s", err)
-		}
-	}
-
 	if utils.IsTTY() {
 		fmt.Fprint(os.Stderr, "\x1b[2m")
 	}
@@ -265,8 +270,14 @@ func (cmd *Command) processFile(f *os.File) (err error) {
 			return fmt.Errorf("error creating directory: %s", err)
 		}
 
-		fName := filepath.Join(cmd.Output, "api."+gen.Endpoint.Name+".go")
-		f, err := os.OpenFile(fName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+		var fName string
+		if gen.Endpoint.Type == "core" {
+			fName = filepath.Join(cmd.Output, "api."+gen.Endpoint.Name+".go")
+		} else {
+			fName = filepath.Join(cmd.Output, "api."+gen.Endpoint.Type+"."+gen.Endpoint.Name+".go")
+		}
+
+		f, err := os.OpenFile(fName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
 		if err != nil {
 			return fmt.Errorf("error creating file: %s", err)
 		}
@@ -281,129 +292,3 @@ func (cmd *Command) processFile(f *os.File) (err error) {
 
 	return nil
 }
-
-func (cmd *Command) processAPIConstructor(endpoints []*Endpoint) (err error) {
-	var b bytes.Buffer
-
-	var namespaces = []string{"Cat", "Cluster", "Indices", "Ingest", "Nodes", "Remote", "Snapshot", "Tasks"}
-
-	b.WriteString("// Code generated")
-	if EsVersion != "" || GitCommit != "" || GitTag != "" {
-		b.WriteString(fmt.Sprintf(" from specification version %s", EsVersion))
-		if GitCommit != "" {
-			b.WriteString(fmt.Sprintf(" (%s", GitCommit))
-			if GitTag != "" {
-				b.WriteString(fmt.Sprintf("|%s", GitTag))
-			}
-			b.WriteString(")")
-		}
-	}
-	b.WriteString(": DO NOT EDIT\n")
-	b.WriteString("\n")
-
-	b.WriteString(`package esapi
-
-// API contains the Elasticsearch APIs
-//
-type API struct {
-`)
-	for _, n := range namespaces {
-		b.WriteString(fmt.Sprintf("\t%[1]s *%[1]s\n", n))
-	}
-
-	b.WriteString("\n")
-
-	for _, e := range endpoints {
-		skip := false
-		name := e.MethodWithNamespace()
-
-		for _, n := range namespaces {
-			if strings.HasPrefix(name, n) {
-				skip = true
-			}
-		}
-		if !skip {
-			b.WriteString(fmt.Sprintf("\t%[1]s %[1]s\n", name))
-		}
-	}
-
-	b.WriteString(`}` + "\n\n")
-
-	for _, n := range namespaces {
-		b.WriteString(`// ` + n + ` contains the ` + n + ` APIs` + "\n")
-		b.WriteString(`type ` + n + ` struct {` + "\n")
-		for _, e := range endpoints {
-			ns := e.Namespace()
-			if ns == n {
-				b.WriteString(fmt.Sprintf("\t%s %s\n", e.MethodName(), e.MethodWithNamespace()))
-			}
-		}
-		b.WriteString("}\n\n")
-	}
-
-	b.WriteString(`// New creates new API
-//
-func New(t Transport) *API {
-	return &API{
-`)
-
-	for _, e := range endpoints {
-		skip := false
-		name := e.MethodWithNamespace()
-
-		for _, n := range namespaces {
-			if strings.HasPrefix(name, n) {
-				skip = true
-			}
-		}
-		if !skip {
-			b.WriteString(fmt.Sprintf("\t\t%[1]s: new%[1]sFunc(t),\n", name))
-		}
-	}
-
-	for _, n := range namespaces {
-		b.WriteString(fmt.Sprintf("\t\t%[1]s: &%[1]s{\n", n))
-		for _, e := range endpoints {
-			ns := e.Namespace()
-			if ns == n {
-				b.WriteString(fmt.Sprintf("\t\t\t%s: new%sFunc(t),\n", e.MethodName(), e.MethodWithNamespace()))
-			}
-		}
-		b.WriteString("\t\t},\n")
-	}
-
-	b.WriteString(`	}
-}
-`)
-
-	if cmd.Gofmt {
-		out, err := imports.Process(
-			"esapi/api._.go",
-			b.Bytes(),
-			&imports.Options{
-				AllErrors:  true,
-				Comments:   true,
-				FormatOnly: false,
-				TabIndent:  true,
-				TabWidth:   1,
-			})
-		if err != nil {
-			return err
-		}
-		b = *bytes.NewBuffer(out)
-	}
-
-	fname := filepath.Join(cmd.Output, "api._.go")
-	f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
-	if err != nil {
-		return fmt.Errorf("error creating file: %s", err)
-	}
-	_, err = io.Copy(f, &b)
-	if err != nil {
-		return fmt.Errorf("error copying output: %s", err)
-	}
-	if err := f.Close(); err != nil {
-		return fmt.Errorf("error closing file: %s", err)
-	}
-	return nil
-}
diff --git a/internal/build/cmd/generate/commands/gensource/debug.go b/internal/build/cmd/generate/commands/gensource/debug.go
new file mode 100644
index 0000000000..db9919fb3f
--- /dev/null
+++ b/internal/build/cmd/generate/commands/gensource/debug.go
@@ -0,0 +1,108 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package gensource
+
+import (
+	"fmt"
+	"math"
+	"strings"
+	"text/tabwriter"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+)
+
+// DebugInfo returns information about the endpoint as a string.
+//
+func (e *Endpoint) DebugInfo() string {
+	var out strings.Builder
+	w := tabwriter.NewWriter(&out, 0, 0, 1, ' ', 0)
+
+	fmt.Fprintln(&out, strings.Repeat("─", utils.TerminalWidth()))
+	fmt.Fprintf(&out, "API: %s (%s:%s)\n", e.MethodWithNamespace(), e.Type, e.Name)
+	fmt.Fprintf(&out, "%s\n", e.Documentation.Description[0:int(math.Min(float64(80), float64(len(e.Documentation.Description))))])
+	fmt.Fprintln(&out, strings.Repeat("─", utils.TerminalWidth()))
+
+	fmt.Fprintln(&out, "Paths:")
+	for _, path := range e.URL.Paths {
+		fmt.Fprintf(w, "%6s\t%s", path.Methods[0], path.Path)
+		if path.Deprecated.Version != "" {
+			fmt.Fprintf(w, "\t*deprecated*")
+		}
+		fmt.Fprintf(w, "\n")
+	}
+	w.Flush()
+
+	longestPath := e.URL.Paths[0]
+	for _, v := range e.URL.Paths {
+		if len(v.Path) > len(longestPath.Path) {
+			longestPath = v
+		}
+	}
+
+	if len(longestPath.Parts) > 0 {
+		fmt.Fprintln(&out, "Parts:")
+		for _, part := range longestPath.Parts {
+			fmt.Fprintf(w, "  • %s\t", part.Name)
+			fmt.Fprintf(w, "  %s", part.Type)
+			if part.Required {
+				fmt.Fprint(w, ", required")
+			}
+			if part.Default != nil {
+				fmt.Fprintf(w, ", default: %s", part.Default)
+			}
+			fmt.Fprint(w, "\n")
+		}
+		w.Flush()
+	}
+
+	if len(e.URL.Params) > 0 {
+		fmt.Fprintln(&out, "Params:")
+		for _, param := range e.URL.Params {
+			fmt.Fprintf(w, "  • %s\t %s", param.Name, param.Type)
+			if param.Required {
+				fmt.Fprint(w, ", required")
+			}
+			if param.Type == "enum" {
+				fmt.Fprintf(w, ": %s", strings.Join(param.Options, ", "))
+			}
+			if param.Default != nil {
+				fmt.Fprintf(w, ", default: %s", param.Default)
+			}
+			fmt.Fprint(w, "\n")
+		}
+		w.Flush()
+	}
+
+	if e.Body != nil {
+		fmt.Fprintln(&out, "Body:")
+		if e.Body.Description != "" {
+			fmt.Fprintf(&out, "  %s.", e.Body.Description)
+		}
+		if e.Body.Required {
+			fmt.Fprintf(&out, " *Required*")
+		} else {
+			fmt.Fprintf(&out, " Optional")
+		}
+		if e.Body.ContentType != "" {
+			fmt.Fprintf(&out, ", format: %s", e.Body.ContentType)
+		}
+		fmt.Fprintf(&out, "\n")
+	}
+
+	return out.String()
+}
diff --git a/internal/cmd/generate/commands/gensource/descriptions.go b/internal/build/cmd/generate/commands/gensource/descriptions.go
old mode 100755
new mode 100644
similarity index 95%
rename from internal/cmd/generate/commands/gensource/descriptions.go
rename to internal/build/cmd/generate/commands/gensource/descriptions.go
index 3307e341f5..75d82a8467
--- a/internal/cmd/generate/commands/gensource/descriptions.go
+++ b/internal/build/cmd/generate/commands/gensource/descriptions.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gensource
 
 var apiDescriptionsYAML = `
@@ -241,6 +258,11 @@ indices.clear_cache:
   description: |-
     Clears all or specific caches for one or more indices.
 
+indices.clone:
+  # https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-clone-index.html
+  description: |-
+    Clones an existing index into a new index.
+
 indices.close:
   # http://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
   description: |-
@@ -529,6 +551,11 @@ scripts_painless_execute:
   description: |-
     Allows an arbitrary script to be executed and a result to be returned
 
+scripts_painless_context:
+  # https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-execute-api.html
+  description: |-
+    Allows to query context information.
+
 scroll:
   # http://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html
   description: |-
diff --git a/internal/cmd/generate/commands/gensource/generator.go b/internal/build/cmd/generate/commands/gensource/generator.go
old mode 100755
new mode 100644
similarity index 73%
rename from internal/cmd/generate/commands/gensource/generator.go
rename to internal/build/cmd/generate/commands/gensource/generator.go
index 549ffe4252..6b5255fa39
--- a/internal/cmd/generate/commands/gensource/generator.go
+++ b/internal/build/cmd/generate/commands/gensource/generator.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gensource
 
 import (
@@ -9,7 +26,7 @@ import (
 
 	"golang.org/x/tools/imports"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 // Generator represents the "gensource" generator.
@@ -72,7 +89,23 @@ func (g *Generator) w(s string) {
 }
 
 func (g *Generator) genHeader() {
-	g.w("// Code generated")
+	g.w(`// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.` + "\n")
+	g.w("//\n// Code generated")
 	if EsVersion != "" {
 		g.w(fmt.Sprintf(" from specification version %s", EsVersion))
 	}
@@ -114,20 +147,28 @@ func new` + g.Endpoint.MethodWithNamespace() + `Func(t Transport) ` + g.Endpoint
 func (g *Generator) genMethodDefinition() {
 	g.w("\n// ----- API Definition -------------------------------------------------------\n\n")
 
-	if g.Endpoint.Description != "" {
-		words := strings.Split(g.Endpoint.Description, " ")
-		initial := strings.ToLower(words[0:1][0])
-		description := initial + " " + strings.Join(words[1:], " ")
-		lines := strings.Split(description, "\n")
-
-		g.w(`// ` + g.Endpoint.MethodWithNamespace() + " " + lines[0:1][0])
-		for _, line := range lines[1:] {
-			g.w("\n// " + line)
+	if g.Endpoint.Type == "xpack" {
+		g.w(`// ` + g.Endpoint.MethodWithNamespace() + " - " + g.Endpoint.Documentation.Description)
+	} else {
+		if g.Endpoint.Documentation.Description != "" {
+			words := strings.Split(g.Endpoint.Documentation.Description, " ")
+			initial := strings.ToLower(words[0:1][0])
+			description := initial + " " + strings.Join(words[1:], " ")
+			lines := strings.Split(description, "\n")
+
+			g.w(`// ` + g.Endpoint.MethodWithNamespace() + " " + lines[0:1][0])
+			for _, line := range lines[1:] {
+				g.w("\n// " + line)
+			}
 		}
 	}
 
-	if g.Endpoint.Documentation != "" {
-		g.w("\n//\n" + `// See full documentation at ` + g.Endpoint.Documentation + ".")
+	if g.Endpoint.Stability != "stable" {
+		g.w("\n//\n// This API is " + g.Endpoint.Stability + ".")
+	}
+
+	if g.Endpoint.Documentation.URL != "" {
+		g.w("\n//\n" + `// See full documentation at ` + g.Endpoint.Documentation.URL + ".")
 	}
 
 	g.w(`
@@ -167,24 +208,32 @@ func (g *Generator) genRequestStruct() {
 // ` + g.Endpoint.MethodWithNamespace() + `Request configures the ` + g.Endpoint.HumanMethodWithNamespace() + ` API request.
 //
 type ` + g.Endpoint.MethodWithNamespace() + `Request struct {`)
-
 	specialFields := []string{"index", "type", "id"}
 	for _, n := range specialFields {
-		if param, ok := g.Endpoint.URL.Parts[n]; ok {
+		if param, ok := g.Endpoint.URL.AllParts[n]; ok {
 			g.w("\n\t" + param.GoName())
 			g.w("\t" + param.GoType(true))
 		}
 	}
 
+	if len(g.Endpoint.URL.AllParts) > 0 {
+		g.w("\n")
+	}
+
 	if g.Endpoint.Body != nil {
 		g.w("\n\tBody io.Reader")
 	}
 
-	if len(g.Endpoint.URL.Parts) > 0 || g.Endpoint.Body != nil {
+	if len(g.Endpoint.URL.AllParts) > 0 || g.Endpoint.Body != nil {
 		g.w("\n")
 	}
 
-	for _, p := range g.Endpoint.URL.Parts {
+	for _, name := range g.Endpoint.URL.PartNamesSorted {
+		p, ok := g.Endpoint.URL.AllParts[name]
+		if !ok {
+			panic(fmt.Sprintf("Part %q not found", name))
+		}
+
 		skip := false
 		for _, v := range specialFields {
 			if p.Name == v {
@@ -196,16 +245,20 @@ type ` + g.Endpoint.MethodWithNamespace() + `Request struct {`)
 		}
 		g.w("\n\t" + p.GoName())
 		g.w("\t" + p.GoType(true))
+
+	}
+
+	if len(g.Endpoint.URL.AllParts) > 0 {
+		g.w("\n")
 	}
 
-	// TODO: Sort params beginning with underscore correctly
 	for _, name := range g.Endpoint.URL.ParamNamesSorted {
 		p, ok := g.Endpoint.URL.Params[name]
 		if !ok {
 			panic(fmt.Sprintf("Parameter %q not found", name))
 		}
 
-		if _, ok := g.Endpoint.URL.Parts[name]; ok {
+		if _, ok := g.Endpoint.URL.AllParts[name]; ok {
 			continue // skip params which are also parts
 		}
 
@@ -218,6 +271,8 @@ type ` + g.Endpoint.MethodWithNamespace() + `Request struct {`)
 	g.w("\n\tErrorTrace\tbool")
 	g.w("\n\tFilterPath\t[]string\n")
 
+	g.w("\n\n\tHeader\thttp.Header\n")
+
 	g.w("\n\tctx context.Context\n}\n")
 }
 
@@ -311,19 +366,6 @@ func (f ` + g.Endpoint.MethodWithNamespace() + `) WithContext(v context.Context)
 		return b.String()
 	}
 
-	// Generate With... methods for parts
-	for _, pName := range g.Endpoint.URL.PartNamesSorted {
-		if p, ok := g.Endpoint.URL.Parts[pName]; ok {
-			if skipRequiredArgs[p.Name] && p.Name != "type" {
-				continue
-			}
-
-			g.w(methodBody(g.Endpoint, p))
-		} else {
-			g.w(`// TODO: ` + p.Name)
-		}
-	}
-
 	// Generate WithBody method
 	if b := g.Endpoint.Body; b != nil {
 		// Do not add the option when body is part of the method signature
@@ -340,9 +382,22 @@ func (f ` + g.Endpoint.MethodWithNamespace() + `) WithBody(v io.Reader) func(*`
 		}
 	}
 
+	// Generate With... methods for parts
+	for _, pName := range g.Endpoint.URL.PartNamesSorted {
+		if p, ok := g.Endpoint.URL.AllParts[pName]; ok {
+			if skipRequiredArgs[p.Name] && p.Name != "type" {
+				continue
+			}
+
+			g.w(methodBody(g.Endpoint, p))
+		} else {
+			g.w(`// TODO: ` + p.Name)
+		}
+	}
+
 	// Generate With... methods for params
 	for _, pName := range g.Endpoint.URL.ParamNamesSorted {
-		if _, ok := g.Endpoint.URL.Parts[pName]; ok {
+		if _, ok := g.Endpoint.URL.AllParts[pName]; ok {
 			continue // skip params which are also parts
 		}
 		if p, ok := g.Endpoint.URL.Params[pName]; ok {
@@ -393,6 +448,36 @@ func (f ` + g.Endpoint.MethodWithNamespace() + `) WithFilterPath(v ...string) fu
 		r.FilterPath = v
 	}
 }
+`)
+
+	// Generate methods for HTTP headers
+	g.w(`
+// WithHeader adds the headers to the HTTP request.
+//
+func (f ` + g.Endpoint.MethodWithNamespace() + `) WithHeader(h map[string]string) func(*` + g.Endpoint.MethodWithNamespace() + `Request) {
+	return func(r *` + g.Endpoint.MethodWithNamespace() + `Request) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		for k, v := range h {
+			r.Header.Add(k, v)
+		}
+	}
+}
+`)
+
+	// Generate methods for the X-Opaque-ID header
+	g.w(`
+// WithOpaqueID adds the X-Opaque-Id header to the HTTP request.
+//
+func (f ` + g.Endpoint.MethodWithNamespace() + `) WithOpaqueID(s string) func(*` + g.Endpoint.MethodWithNamespace() + `Request) {
+	return func(r *` + g.Endpoint.MethodWithNamespace() + `Request) {
+		if r.Header == nil {
+			r.Header = make(http.Header)
+		}
+		r.Header.Set("X-Opaque-Id", s)
+	}
+}
 `)
 }
 
@@ -406,7 +491,6 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 		params  map[string]string
 	)` + "\n\n")
 
-	// Generate the HTTP method
 	switch g.Endpoint.Name {
 	case "index":
 		g.w("\t")
@@ -417,7 +501,16 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 	}`)
 		g.w("\n\n")
 	default:
-		g.w("\t" + `method = "` + g.Endpoint.Methods[0] + `"` + "\n\n")
+		var httpMethod string
+		// If endpoint has both GET and POST available
+		// Prefer POST usage in order to prevent go routine leak
+		// See https://github.com/golang/go/issues/29246
+		if g.Endpoint.URL.ContainsMethods("GET", "POST") {
+			httpMethod = "POST"
+		} else {
+			httpMethod = g.Endpoint.URL.Paths[0].Methods[0]
+		}
+		g.w("\t" + `method = "` + httpMethod + `"` + "\n\n")
 	}
 
 	// Get default part values for specific APIs
@@ -425,7 +518,7 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 	var defparts bool
 	switch g.Endpoint.Name {
 	case "index", "create", "delete", "explain", "exists", "get", "get_source", "update", "termvectors":
-		for _, p := range g.Endpoint.URL.Parts {
+		for _, p := range g.Endpoint.URL.AllParts {
 			if p.Default != nil {
 				var fieldName string
 				var fieldValue string
@@ -469,25 +562,25 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 
 		pathGrow.WriteString(`	path.Grow(`)
 
-		if len(g.Endpoint.URL.Parts) < 1 {
-			if g.Endpoint.URL.Path == "" {
-				panic(fmt.Sprintf("FAIL: %q: empty endpoint\n", g.Endpoint.Name))
+		// FIXME: Select longest path based on number of template entries, not string length
+		longestPath := g.Endpoint.URL.Paths[0]
+		for _, v := range g.Endpoint.URL.Paths {
+			if len(v.Path) > len(longestPath.Path) {
+				longestPath = v
 			}
-			pathGrow.WriteString(`len("` + g.Endpoint.URL.Path + `")`)
-			pathContent.WriteString(`	path.WriteString("` + g.Endpoint.URL.Path + `")` + "\n")
+		}
 
-		} else {
-			// FIXME: Select longest path based on number of template entries, not string length
-			longestPath := g.Endpoint.URL.Paths[0]
-			for _, v := range g.Endpoint.URL.Paths {
-				if len(v) > len(longestPath) {
-					longestPath = v
-				}
+		if len(longestPath.Parts) < 1 {
+			if len(g.Endpoint.URL.Paths) < 1 {
+				panic(fmt.Sprintf("FAIL: %q: empty endpoint\n", g.Endpoint.Name))
 			}
+			pathGrow.WriteString(`len("` + longestPath.Path + `")`)
+			pathContent.WriteString(`	path.WriteString("` + longestPath.Path + `")` + "\n")
 
+		} else {
 			pathParts := make([]string, 0)
 			apiArgs := g.Endpoint.RequiredArguments()
-			for _, v := range strings.Split(longestPath, "/") {
+			for _, v := range strings.Split(longestPath.Path, "/") {
 				if v != "" {
 					pathParts = append(pathParts, v)
 				}
@@ -505,12 +598,18 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 						pathGrow.WriteString(`1 + `)
 						pathContent.WriteString(`	path.WriteString("/")` + "\n")
 						switch a.Type {
+						case "int":
+							pathGrow.WriteString(`len(strconv.Itoa(*r.` + p + `)) + `)
+							pathContent.WriteString(`	path.WriteString(strconv.Itoa(*r.` + p + `))` + "\n")
 						case "string":
 							pathGrow.WriteString(`len(r.` + p + `) + `)
 							pathContent.WriteString(`	path.WriteString(r.` + p + `)` + "\n")
 						case "list":
 							pathGrow.WriteString(`len(strings.Join(r.` + p + `, ",")) + `)
 							pathContent.WriteString(`	path.WriteString(strings.Join(r.` + p + `, ","))` + "\n")
+						case "long":
+							pathGrow.WriteString(`len(strconv.Itoa(*r.` + p + `)) + `)
+							pathContent.WriteString(`	path.WriteString(strconv.Itoa(*r.` + p + `))` + "\n")
 						default:
 							panic(fmt.Sprintf("FAIL: %q: unexpected type %q for URL part %q\n", g.Endpoint.Name, a.Type, a.Name))
 						}
@@ -520,7 +619,8 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 
 				// Optional arguments
 				if p == "" {
-					for _, a := range g.Endpoint.URL.Parts {
+					for _, a := range longestPath.Parts {
+						// fmt.Printf("a: %+v\n", a)
 						if strings.HasPrefix(v, "{") && a.Name == r.Replace(v) {
 							p = a.GoName()
 
@@ -537,6 +637,13 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 								pathContent.WriteString(`		path.WriteString("/")` + "\n")
 								pathContent.WriteString(`		path.WriteString(strings.Join(r.` + p + `, ","))` + "\n")
 								pathContent.WriteString(`	}` + "\n")
+							case "int", "long":
+								pathContent.WriteString(`	if r.` + p + ` != nil {` + "\n")
+								pathContent.WriteString(`		value := strconv.FormatInt(int64(*r.` + p + `), 10)` + "\n")
+								pathContent.WriteString(`		path.Grow(1 + len(value))` + "\n")
+								pathContent.WriteString(`		path.WriteString("/")` + "\n")
+								pathContent.WriteString(`		path.WriteString(value)` + "\n")
+								pathContent.WriteString(`	}` + "\n")
 							default:
 								panic(fmt.Sprintf("FAIL: %q: unexpected type %q for URL part %q\n", g.Endpoint.Name, a.Type, a.Name))
 							}
@@ -613,6 +720,12 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 			case "*int":
 				fieldCondition = `r.` + fieldName + ` != nil`
 				fieldValue = `strconv.FormatInt(int64(*r.` + fieldName + `), 10)`
+			case "uint":
+				fieldCondition = `r.` + fieldName + ` != 0`
+				fieldValue = `strconv.FormatUint(uint64(r.` + fieldName + `), 10)`
+			case "*uint":
+				fieldCondition = `r.` + fieldName + ` != 0`
+				fieldValue = `strconv.FormatUint(uint64(*r.` + fieldName + `), 10)`
 			case "[]string":
 				fieldCondition = ` len(r.` + fieldName + `) > 0`
 				fieldValue = `strings.Join(r.` + fieldName + `, ",")`
@@ -663,7 +776,10 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 		httpBody = "nil"
 	}
 
-	g.w(`req, _ := newRequest(method, path.String(), ` + httpBody + `)` + "\n\n")
+	g.w(`req, err := newRequest(method, path.String(), ` + httpBody + `)` + "\n")
+	g.w(`if err != nil {
+		return nil, err
+	}` + "\n\n")
 
 	g.w(`if len(params) > 0 {
 		q := req.URL.Query()
@@ -679,6 +795,18 @@ func (r ` + g.Endpoint.MethodWithNamespace() + `Request) Do(ctx context.Context,
 	}` + "\n\n")
 	}
 
+	g.w(`if len(r.Header) > 0 {
+		if len(req.Header) == 0 {
+			req.Header = r.Header
+		} else {
+			for k, vv := range r.Header {
+				for _, v := range vv {
+					req.Header.Add(k, v)
+				}
+			}
+		}
+	}` + "\n\n")
+
 	g.w(`if ctx != nil {
 		req = req.WithContext(ctx)
 	}` + "\n\n")
diff --git a/internal/build/cmd/generate/commands/gensource/generator_test.go b/internal/build/cmd/generate/commands/gensource/generator_test.go
new file mode 100644
index 0000000000..68847e56ac
--- /dev/null
+++ b/internal/build/cmd/generate/commands/gensource/generator_test.go
@@ -0,0 +1,58 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package gensource_test
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd/generate/commands/gensource"
+)
+
+func TestGenerator(t *testing.T) {
+	t.Run("Output", func(t *testing.T) {
+		f, err := os.Open("testdata/info.json")
+		if err != nil {
+			t.Fatalf("Error: %s", err)
+		}
+
+		endpoint, err := gensource.NewEndpoint(f)
+		if err != nil {
+			t.Fatalf("Error creating endpoint for %q: %s", f.Name(), err)
+		}
+
+		gen := gensource.Generator{Endpoint: endpoint}
+
+		out, err := gen.OutputFormatted()
+		if err != nil {
+			t.Fatalf("Error generating output for %q: %s", f.Name(), err)
+		}
+
+		s, err := ioutil.ReadAll(out)
+		if err != nil {
+			t.Fatalf("Error reading output for %q: %s", f.Name(), err)
+		}
+		// t.Logf("\n%s\n", s)
+
+		if !strings.Contains(string(s), "func newInfoFunc(t Transport) Info {") {
+			t.Error("Incorrect output")
+		}
+	})
+}
diff --git a/internal/cmd/generate/commands/gensource/model.go b/internal/build/cmd/generate/commands/gensource/model.go
old mode 100755
new mode 100644
similarity index 50%
rename from internal/cmd/generate/commands/gensource/model.go
rename to internal/build/cmd/generate/commands/gensource/model.go
index a4995124d4..e543507f3e
--- a/internal/cmd/generate/commands/gensource/model.go
+++ b/internal/build/cmd/generate/commands/gensource/model.go
@@ -1,15 +1,34 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gensource
 
 import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"os"
 	"sort"
 	"strings"
+	"unicode"
 
 	"gopkg.in/yaml.v2"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 var (
@@ -29,25 +48,136 @@ func NewEndpoint(f io.Reader) (*Endpoint, error) {
 	var endpoint Endpoint
 	var spec map[string]Endpoint
 
+	var xpackNamespaces = []string{
+		"async_search",
+		"autoscaling",
+		"cat.ml_data_frame_analytics",
+		"cat.ml_datafeeds",
+		"cat.ml_jobs",
+		"cat.ml_trained_models",
+		"cat.transforms",
+		"ccr",
+		"close_point_in_time",
+		"data_frame_transform_deprecated",
+		"enrich",
+		"eql",
+		"graph",
+		"ilm",
+		"indices.create_data_stream",
+		"indices.data_streams_stats",
+		"indices.delete_data_stream",
+		"indices.freeze",
+		"indices.get_data_stream",
+		"indices.migrate_to_data_stream",
+		"indices.promote_data_stream",
+		"indices.reload_search_analyzers",
+		"indices.unfreeze",
+		"license",
+		"logstash",
+		"migration",
+		"ml",
+		"monitoring",
+		"open_point_in_time",
+		"rollup",
+		"searchable_snapshots",
+		"security",
+		"slm",
+		"sql",
+		"ssl",
+		"text_structure",
+		"transform",
+		"watcher",
+		"xpack.info",
+		"xpack.usage",
+	}
+
 	if err := json.NewDecoder(f).Decode(&spec); err != nil {
 		return nil, err
 	}
+
 	for name, e := range spec {
 		endpoint = e
 		endpoint.Name = name
+		endpoint.URL.Params = endpoint.Params
 	}
-	for partName, p := range endpoint.URL.Parts {
-		p.Endpoint = &endpoint
-		p.Name = partName
+
+	if fpath, ok := f.(*os.File); ok {
+		if strings.Contains(fpath.Name(), "x-pack") {
+			endpoint.Type = "xpack"
+		}
+		for _, namespace := range xpackNamespaces {
+			if strings.Contains(fpath.Name(), namespace) {
+				endpoint.Type = "xpack"
+			}
+		}
+	}
+	if endpoint.Type == "" {
+		endpoint.Type = "core"
+	}
+
+	endpoint.URL.AllParts = make(map[string]*Part)
+
+	for _, path := range endpoint.URL.Paths {
+		for partName, part := range path.Parts {
+			part.Endpoint = &endpoint
+			part.Name = partName
+		}
+	}
+
+	var params [][]string
+	for _, path := range endpoint.URL.Paths {
+		var parts []string
+		for partName := range path.Parts {
+			parts = append(parts, partName)
+		}
+		params = append(params, parts)
 	}
+
+	var paramsCounter = make(map[string]int)
+	for _, pp := range params {
+		for _, p := range pp {
+			paramsCounter[p] += 1
+		}
+	}
+
+	// Update the required field of path parts
+	for _, path := range endpoint.URL.Paths {
+		for partName, part := range path.Parts {
+			if p, ok := paramsCounter[partName]; ok {
+				if p == len(params) {
+					part.Required = true
+				}
+			}
+		}
+	}
+
 	for paramName, p := range endpoint.URL.Params {
 		p.Endpoint = &endpoint
 		p.Name = paramName
 	}
 
+	// Update the AllParts field
+	var partSeen = make(map[string]bool)
+	for _, path := range endpoint.URL.Paths {
+		for partName, part := range path.Parts {
+			if !partSeen[partName] {
+				endpoint.URL.AllParts[partName] = part
+			}
+			partSeen[partName] = true
+		}
+	}
+
+	// Fix up the documentation property (X-Pack spec related); TODO: PR
+	if !strings.HasPrefix(endpoint.Documentation.URL, "http") {
+		if endpoint.Type == "xpack" && endpoint.Documentation.Description == "" && endpoint.Documentation.URL != "" {
+			endpoint.Documentation.Description = endpoint.Documentation.URL
+		}
+		endpoint.Documentation.URL = ""
+	}
+
 	var partNames []string
-	for _, param := range endpoint.URL.Parts {
-		partNames = append(partNames, param.Name)
+	for param := range paramsCounter {
+		partNames = append(partNames, param)
 	}
 	sort.Slice(partNames, func(i, j int) bool {
 		return strings.Replace(partNames[i], "_", "", 1) < strings.Replace(partNames[j], "_", "", 1)
@@ -63,17 +193,19 @@ func NewEndpoint(f io.Reader) (*Endpoint, error) {
 	})
 	endpoint.URL.ParamNamesSorted = paramNames
 
-	for _, param := range endpoint.URL.Parts {
-		if param.Name == "type" {
-			param.Default = "_doc"
+	for _, path := range endpoint.URL.Paths {
+		for _, part := range path.Parts {
+			if part.Name == "type" {
+				part.Default = "_doc"
+			}
 		}
 	}
 
-	if info, ok := apiDescriptions[endpoint.Name]; ok {
-		if desc, ok := info.(map[interface{}]interface{})["description"].(string); ok {
-			endpoint.Description = desc
-		}
-	}
+	// if info, ok := apiDescriptions[endpoint.Name]; ok {
+	// 	if desc, ok := info.(map[interface{}]interface{})["description"].(string); ok {
+	// 		endpoint.Documentation.Description = desc
+	// 	}
+	// }
 
 	return &endpoint, nil
 }
@@ -82,12 +214,18 @@ func NewEndpoint(f io.Reader) (*Endpoint, error) {
 //
 type Endpoint struct {
 	Name string `json:"-"`
+	Type string `json:"-"`
+
+	Documentation struct {
+		URL         string `json:"url"`
+		Description string `json:"description"`
+	} `json:"documentation"`
+
+	Stability string `json:"stability"`
 
-	Description   string   `json:"-"`
-	Documentation string   `json:"documentation"`
-	Methods       []string `json:"methods"`
-	URL           *URL     `json:"url"`
-	Body          *Body    `json:"body"`
+	URL    *URL              `json:"url"`
+	Params map[string]*Param `json:"params"`
+	Body   *Body             `json:"body"`
 }
 
 // URL represents API endpoint URL.
@@ -95,15 +233,30 @@ type Endpoint struct {
 type URL struct {
 	Endpoint *Endpoint `json:"-"`
 
-	Path   string            `json:"path"`
-	Paths  []string          `json:"paths"`
-	Parts  map[string]*Part  `json:"parts"`
+	Paths           []Path `json:"paths"`
+	DeprecatedPaths []struct {
+		Path        string `json:"path"`
+		Version     string `json:"version"`
+		Description string `json:"description"`
+	} `json:"deprecated_paths"`
 	Params map[string]*Param `json:"params"`
 
+	AllParts         map[string]*Part
 	PartNamesSorted  []string
 	ParamNamesSorted []string
 }
 
+// Path represents URL path
+type Path struct {
+	Path       string           `json:"path"`
+	Methods    []string         `json:"methods"`
+	Parts      map[string]*Part `json:"parts"`
+	Deprecated struct {
+		Version     string `json:"version"`
+		Description string `json:"description"`
+	}
+}
+
 // Part represents part of the API endpoint URL.
 //
 type Part struct {
@@ -158,7 +311,7 @@ type MethodArgument struct {
 //
 func (e *Endpoint) Namespace() string {
 	ep := strings.Split(e.Name, ".")
-	return strings.Title(ep[0])
+	return utils.NameToGo(ep[0])
 }
 
 // MethodName returns the API endpoint method name.
@@ -181,40 +334,46 @@ func (e *Endpoint) MethodName() string {
 // MethodWithNamespace returns the API endpoint method name with namespace.
 //
 func (e *Endpoint) MethodWithNamespace() string {
-	ep := strings.Split(e.Name, ".")
-	ns := make([]string, len(ep))
-	for _, v := range ep {
-		m := strings.Split(v, "_")
-		mn := make([]string, len(m))
-		for _, vv := range m {
-			mn = append(mn, strings.Title(vv))
-		}
-		ns = append(ns, strings.Join(mn, ""))
-	}
-	return strings.Join(ns, "")
+	return utils.APIToGo(e.Name)
 }
 
 // HumanMethodWithNamespace returns the API endpoint method name in humanized form.
 //
 func (e *Endpoint) HumanMethodWithNamespace() string {
-	ep := strings.Split(e.Name, ".")
-	ns := make([]string, len(ep))
-	for _, v := range ep {
-		m := strings.Split(v, "_")
-		mn := make([]string, len(m))
-		for _, vv := range m {
-			mn = append(mn, strings.Title(vv))
+	var (
+		src = e.MethodWithNamespace()
+		out string
+	)
+	for i, l := range src {
+		if unicode.IsUpper(l) && i > 0 {
+			if i+2 <= len(src) && unicode.IsUpper([]rune(src[i+1 : i+2])[0]) {
+				out += string(l)
+			} else {
+				out += " " + string(l)
+			}
+		} else {
+			out += string(l)
 		}
-		ns = append(ns, strings.Join(mn, " "))
 	}
-	return strings.TrimSpace(strings.Join(ns, ""))
+	return out
 }
 
 // RequiredArguments return the list of required method arguments.
 //
 func (e *Endpoint) RequiredArguments() []MethodArgument {
 	var args = make([]MethodArgument, 0)
-	var prominentArgs = []string{"index", "type", "id", "repository", "snapshot"}
+	var prominentArgs = []string{
+		"index",
+		"type",
+		"id",
+		"repository",
+		"snapshot",
+		"snapshot_id",
+		"calendar_id",
+		"job_id",
+		"username",
+		"name",
+	}
 
 	var contains = func(s string) bool {
 		for _, v := range args {
@@ -227,12 +386,13 @@ func (e *Endpoint) RequiredArguments() []MethodArgument {
 
 	// Return the prominent arguments first
 	for _, d := range prominentArgs {
-		for _, p := range e.URL.Parts {
+		for _, p := range e.URL.Paths[0].Parts {
 			if p.Name != d {
 				continue
 			}
 			if p.Required {
 				args = append(args, MethodArgument{
+					Endpoint:    e,
 					Name:        p.Name,
 					Type:        p.Type,
 					Description: p.Description,
@@ -242,6 +402,7 @@ func (e *Endpoint) RequiredArguments() []MethodArgument {
 			// Make the 'type' required for selected APIs
 			if p.Name == "type" && (e.Name == "index" || e.Name == "create") {
 				args = append(args, MethodArgument{
+					Endpoint:    e,
 					Name:        p.Name,
 					Type:        p.Type,
 					Description: p.Description,
@@ -254,18 +415,20 @@ func (e *Endpoint) RequiredArguments() []MethodArgument {
 	// Return the body after prominent arguments
 	if e.Body != nil && e.Body.Required {
 		args = append(args, MethodArgument{
+			Endpoint:    e,
 			Name:        "body",
 			Description: e.Body.Description,
 		})
 	}
 
 	// Return rest of the URL parts
-	for _, p := range e.URL.Parts {
+	for _, p := range e.URL.Paths[0].Parts {
 		if contains(p.Name) {
 			continue
 		}
 		if p.Required {
 			args = append(args, MethodArgument{
+				Endpoint:    e,
 				Name:        p.Name,
 				Type:        p.Type,
 				Description: p.Description,
@@ -281,6 +444,7 @@ func (e *Endpoint) RequiredArguments() []MethodArgument {
 		}
 		if p.Required {
 			args = append(args, MethodArgument{
+				Endpoint:    e,
 				Name:        p.Name,
 				Type:        p.Type,
 				Description: p.Description,
@@ -301,7 +465,7 @@ func (p *Part) GoName() string {
 	case p.Name == "context":
 		return "ScriptContext"
 	default:
-		return utils.NameToGo(p.Name)
+		return utils.NameToGo(p.Name, p.Endpoint.MethodWithNamespace())
 	}
 }
 
@@ -320,7 +484,7 @@ func (p *Param) GoName() string {
 	case p.Name == "q":
 		return "Query"
 	default:
-		return utils.NameToGo(p.Name)
+		return utils.NameToGo(p.Name, p.Endpoint.MethodWithNamespace())
 	}
 }
 
@@ -338,7 +502,7 @@ func (p *Param) GoType(comment ...bool) string {
 // GoName returns a Go name for method argument.
 //
 func (p *MethodArgument) GoName() string {
-	return utils.NameToGo(p.Name)
+	return utils.NameToGo(p.Name, p.Endpoint.MethodWithNamespace())
 }
 
 // GoType returns a Go type for method argument.
@@ -346,3 +510,28 @@ func (p *MethodArgument) GoName() string {
 func (p *MethodArgument) GoType(comment ...bool) string {
 	return utils.TypeToGo(p.Type)
 }
+
+// ContainsMethods return true if every method passed in argument is present in every Path
+func (u *URL) ContainsMethods(methods ...string) bool {
+	for _, path := range u.Paths {
+		// Fast exit if both collections are not the same size
+		if len(methods) != len(path.Methods) {
+			return false
+		}
+
+		// We iterate over every items
+		items := make(map[string]struct{})
+		for _, v := range path.Methods {
+			items[v] = struct{}{}
+		}
+
+		for _, method := range methods {
+			if _, ok := items[method]; ok {
+				continue
+			}
+			return false
+		}
+		continue
+	}
+	return true
+}
\ No newline at end of file
diff --git a/internal/cmd/generate/commands/gensource/overrides.go b/internal/build/cmd/generate/commands/gensource/overrides.go
old mode 100755
new mode 100644
similarity index 67%
rename from internal/cmd/generate/commands/gensource/overrides.go
rename to internal/build/cmd/generate/commands/gensource/overrides.go
index 021b1d07a0..df0882bfca
--- a/internal/cmd/generate/commands/gensource/overrides.go
+++ b/internal/build/cmd/generate/commands/gensource/overrides.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gensource
 
 var (
@@ -91,7 +108,16 @@ func init() {
 	if r.DocumentType != "" {
 		path.WriteString("/")
 		path.WriteString(r.DocumentType)
-	}
+}
+`
+				},
+			},
+			{
+				Matching: []string{"scroll"},
+				Func: func(*Endpoint, ...interface{}) string {
+					return `
+	path.Grow(len("/_search/scroll"))
+	path.WriteString("/_search/scroll")
 `
 				},
 			},
diff --git a/internal/build/cmd/generate/commands/gensource/testdata/info.json b/internal/build/cmd/generate/commands/gensource/testdata/info.json
new file mode 100644
index 0000000000..13fe1f2802
--- /dev/null
+++ b/internal/build/cmd/generate/commands/gensource/testdata/info.json
@@ -0,0 +1,18 @@
+{
+  "info": {
+    "stability": "stable",
+    "documentation": {
+      "url": "http://www.elastic.co/guide/",
+      "description": "Returns basic information about the cluster."
+    },
+    "url": {
+      "paths": [
+        {
+          "path": "/",
+          "methods": ["GET"]
+        }
+      ]
+    },
+    "params": {}
+  }
+}
\ No newline at end of file
diff --git a/internal/build/cmd/generate/commands/genstruct/command.go b/internal/build/cmd/generate/commands/genstruct/command.go
new file mode 100644
index 0000000000..824dffa397
--- /dev/null
+++ b/internal/build/cmd/generate/commands/genstruct/command.go
@@ -0,0 +1,383 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package genstruct
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
+	"go/types"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"golang.org/x/tools/go/packages"
+	"golang.org/x/tools/imports"
+
+	"github.com/spf13/cobra"
+
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+)
+
+var (
+	GitCommit string
+	GitTag    string
+	EsVersion string
+)
+
+var (
+	output *string
+	gofmt  *bool
+	color  *bool
+	debug  *bool
+	info   *bool
+
+	pkgNames []string
+)
+
+func init() {
+	if pkgNamesEnv := os.Getenv("PACKAGE_NAMES"); pkgNamesEnv != "" {
+		pkgNames = strings.Split(pkgNamesEnv, ",")
+	} else {
+		pkgNames = []string{
+			"github.com/elastic/go-elasticsearch/v7/esapi",
+		}
+	}
+
+	output = genapiCmd.Flags().StringP("output", "o", "", "Path to a folder for generated output")
+	gofmt = genapiCmd.Flags().BoolP("gofmt", "f", true, "Format generated output with 'gofmt'")
+	color = genapiCmd.Flags().BoolP("color", "c", true, "Syntax highlight the debug output")
+	debug = genapiCmd.Flags().BoolP("debug", "d", false, "Print the generated source to terminal")
+	info = genapiCmd.Flags().Bool("info", false, "Print the API details to terminal")
+	genapiCmd.Flags().SortFlags = false
+
+	cmd.RegisterCmd(genapiCmd)
+}
+
+var genapiCmd = &cobra.Command{
+	Use:   "apistruct",
+	Short: "Generate the main Go API struct and constructor",
+	Run: func(cmd *cobra.Command, args []string) {
+		command := &Command{
+			Output:         *output,
+			Gofmt:          *gofmt,
+			DebugSource:    *debug,
+			ColorizeSource: *color,
+		}
+		err := command.Execute()
+		if err != nil {
+			utils.PrintErr(err)
+			os.Exit(1)
+		}
+	},
+}
+
+// Command represents the "genapi" command.
+//
+type Command struct {
+	Output         string
+	Gofmt          bool
+	DebugSource    bool
+	ColorizeSource bool
+}
+
+// Execute runs the command.
+//
+func (cmd *Command) Execute() (err error) {
+	EsVersion, err = utils.EsVersion("")
+	if err != nil {
+		return err
+	}
+	GitCommit, err = utils.GitCommit("")
+	if err != nil {
+		return err
+	}
+	GitTag, err = utils.GitTag("")
+	if err != nil {
+		return err
+	}
+	return cmd.processAPIConstructor()
+}
+
+func (cmd *Command) processAPIConstructor() (err error) {
+	var (
+		namespaces []string
+		endpoints  []*types.TypeName
+
+		b bytes.Buffer
+		i int
+		n int
+		m int
+	)
+
+	namespaces = []string{
+		// Core APIs
+		//
+		"Cat",
+		"Cluster",
+		"Indices",
+		"Ingest",
+		"Nodes",
+		"Remote",
+		"Snapshot",
+		"Tasks",
+
+		// XPack APIs
+		//
+		"AsyncSearch",
+		"CCR",
+		"ILM",
+		"License",
+		"Migration",
+		"ML",
+		"Monitoring",
+		"Rollup",
+		"Security",
+		"SQL",
+		"SSL",
+		"Watcher",
+		"XPack",
+	}
+
+	lpkgs, err := packages.Load(&packages.Config{Mode: packages.LoadTypes}, pkgNames...)
+	if err != nil {
+		fmt.Printf("Error loading packages: %s\n", err)
+		return err
+	}
+
+	for _, lpkg := range lpkgs {
+		n++
+
+		if cmd.DebugSource {
+			fmt.Println(lpkg.Types)
+		}
+
+		scope := lpkg.Types.Scope()
+		for _, name := range scope.Names() {
+			m++
+			obj := scope.Lookup(name)
+			// Skip unexported objects
+			if !obj.Exported() {
+				continue
+			}
+
+			// Skip non-structs
+			structObj, ok := obj.Type().Underlying().(*types.Struct)
+			if !ok {
+				continue
+			}
+
+			// Skip non-request objects
+			if !strings.HasSuffix(obj.Name(), "Request") {
+				continue
+			}
+
+			// Append API struct to endpoints
+			endpoints = append(endpoints, obj.(*types.TypeName))
+
+			i++
+			fmt.Printf("%-3d | %s{}\n", i, obj.Name())
+			for j := 0; j < structObj.NumFields(); j++ {
+				field := structObj.Field(j)
+				if cmd.DebugSource {
+					fmt.Printf("        %s %s\n", field.Name(), field.Type())
+				}
+			}
+		}
+	}
+	b.WriteString(`// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//`)
+	b.WriteString("\n")
+	b.WriteString("// Code generated")
+	if EsVersion != "" || GitCommit != "" || GitTag != "" {
+		b.WriteString(fmt.Sprintf(" from specification version %s", EsVersion))
+		if GitCommit != "" {
+			b.WriteString(fmt.Sprintf(" (%s", GitCommit))
+			if GitTag != "" {
+				b.WriteString(fmt.Sprintf("|%s", GitTag))
+			}
+			b.WriteString(")")
+		}
+	}
+	b.WriteString(": DO NOT EDIT\n")
+	b.WriteString("\n")
+
+	b.WriteString(`package esapi
+
+// API contains the Elasticsearch APIs
+//
+type API struct {
+`)
+	for _, n := range namespaces {
+		b.WriteString(fmt.Sprintf("\t%[1]s *%[1]s\n", n))
+	}
+
+	b.WriteString("\n")
+
+	for _, e := range endpoints {
+		skip := false
+		name := strings.ReplaceAll(e.Name(), "Request", "")
+
+		// Skip APIs in namespace
+		for _, n := range namespaces {
+			if strings.HasPrefix(strings.ToLower(name), strings.ToLower(n)) {
+				skip = true
+			}
+		}
+		if !skip {
+			b.WriteString(fmt.Sprintf("\t%[1]s %[1]s\n", name))
+		}
+	}
+
+	b.WriteString(`}` + "\n\n")
+
+	for _, n := range namespaces {
+		b.WriteString(`// ` + n + ` contains the ` + n + ` APIs` + "\n")
+		b.WriteString(`type ` + n + ` struct {` + "\n")
+		for _, e := range endpoints {
+			name := strings.ReplaceAll(e.Name(), "Request", "")
+			if strings.HasPrefix(strings.ToLower(name), strings.ToLower(n)) {
+				methodName := strings.ReplaceAll(name, n, "")
+				// Some methods are equal to the namespace (like 'rollup.rollup')
+				// and we don't want to have an empty string here.
+				if len(methodName) == 0 {
+				    methodName = strings.Replace(name, n, "", 1)
+				}
+				b.WriteString(fmt.Sprintf("\t%s %s\n", methodName, name))
+			}
+		}
+		b.WriteString("}\n\n")
+	}
+
+	b.WriteString(`// New creates new API
+//
+func New(t Transport) *API {
+	return &API{
+`)
+
+	for _, e := range endpoints {
+		skip := false
+		name := strings.ReplaceAll(e.Name(), "Request", "")
+
+		for _, n := range namespaces {
+			if strings.HasPrefix(strings.ToLower(name), strings.ToLower(n)) {
+				skip = true
+			}
+		}
+		if !skip {
+			b.WriteString(fmt.Sprintf("\t\t%[1]s: new%[1]sFunc(t),\n", name))
+		}
+	}
+
+	for _, n := range namespaces {
+		b.WriteString(fmt.Sprintf("\t\t%[1]s: &%[1]s{\n", n))
+		for _, e := range endpoints {
+			name := strings.ReplaceAll(e.Name(), "Request", "")
+			if strings.HasPrefix(strings.ToLower(name), strings.ToLower(n)) {
+				methodName := strings.ReplaceAll(name, n, "")
+				// Some methods are equal to the namespace (like 'rollup.rollup')
+				// and we don't want to have an empty string here.
+				if len(methodName) == 0 {
+				    methodName = strings.Replace(name, n, "", 1)
+				}
+				b.WriteString(fmt.Sprintf("\t\t\t%s: new%sFunc(t),\n", methodName, name))
+			}
+		}
+		b.WriteString("\t\t},\n")
+	}
+
+	b.WriteString(`	}
+}
+`)
+
+	if cmd.Gofmt {
+		out, err := imports.Process(
+			"esapi/api._.go",
+			b.Bytes(),
+			&imports.Options{
+				AllErrors:  true,
+				Comments:   true,
+				FormatOnly: false,
+				TabIndent:  true,
+				TabWidth:   1,
+			})
+		if err != nil {
+			return err
+		}
+		b = *bytes.NewBuffer(out)
+	}
+
+	if cmd.DebugSource {
+		var src io.Reader
+		var buf bytes.Buffer
+		tee := io.TeeReader(bytes.NewReader(b.Bytes()), &buf)
+
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[2m")
+		}
+		fmt.Fprintln(os.Stderr, strings.Repeat("━", utils.TerminalWidth()))
+		if utils.IsTTY() {
+			fmt.Fprint(os.Stderr, "\x1b[0m")
+		}
+		if cmd.ColorizeSource {
+			src, err = utils.Chromatize(tee)
+			if err != nil {
+				return fmt.Errorf("error syntax highligting the output: %s", err)
+			}
+		} else {
+			src = bytes.NewReader(b.Bytes())
+		}
+
+		_, err = io.Copy(os.Stderr, src)
+		if err != nil {
+			return fmt.Errorf("error copying output: %s", err)
+		}
+
+		fmt.Fprintf(os.Stderr, "\n\n")
+	}
+
+	fname := filepath.Join(cmd.Output, "api._.go")
+	f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		return fmt.Errorf("error creating file: %s", err)
+	}
+	_, err = io.Copy(f, &b)
+	if err != nil {
+		return fmt.Errorf("error copying output: %s", err)
+	}
+	if err := f.Close(); err != nil {
+		return fmt.Errorf("error closing file: %s", err)
+	}
+	return nil
+}
diff --git a/internal/cmd/generate/commands/gentests/.gitignore b/internal/build/cmd/generate/commands/gentests/.gitignore
old mode 100755
new mode 100644
similarity index 100%
rename from internal/cmd/generate/commands/gentests/.gitignore
rename to internal/build/cmd/generate/commands/gentests/.gitignore
diff --git a/internal/cmd/generate/commands/gentests/command.go b/internal/build/cmd/generate/commands/gentests/command.go
old mode 100755
new mode 100644
similarity index 85%
rename from internal/cmd/generate/commands/gentests/command.go
rename to internal/build/cmd/generate/commands/gentests/command.go
index a8611d4db8..1b541f8055
--- a/internal/cmd/generate/commands/gentests/command.go
+++ b/internal/build/cmd/generate/commands/gentests/command.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gentests
 
 //go:generate go run gen_api_registry.go
@@ -15,8 +32,8 @@ import (
 	"github.com/spf13/cobra"
 	yaml "gopkg.in/yaml.v2"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/commands"
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 var (
@@ -48,12 +65,12 @@ func init() {
 	gentestsCmd.MarkFlagRequired("input")
 	gentestsCmd.MarkFlagRequired("output")
 
-	commands.RegisterCmd(gentestsCmd)
+	cmd.RegisterCmd(gentestsCmd)
 }
 
 var gentestsCmd = &cobra.Command{
-	Use:   "tests",
-	Short: "Generate Go integration tests from Elasticsearch common test suite",
+	Use:   "apitests",
+	Short: "Generate the Go integration tests from the Elasticsearch common test suite",
 	Run: func(cmd *cobra.Command, args []string) {
 		command := &Command{
 			Input:          *input,
@@ -274,7 +291,7 @@ func (cmd *Command) processFile(fpath string) (err error) {
 			return fmt.Errorf("error creating directory: %s", err)
 		}
 
-		fName := filepath.Join(cmd.Output, gen.TestSuite.Filename()+"__test.go")
+		fName := filepath.Join(cmd.Output, gen.TestSuite.Filename()+"_test.go")
 		f, err := os.OpenFile(fName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
 		if err != nil {
 			return fmt.Errorf("error creating file: %s", err)
diff --git a/internal/cmd/generate/commands/gentests/debug.go b/internal/build/cmd/generate/commands/gentests/debug.go
old mode 100755
new mode 100644
similarity index 71%
rename from internal/cmd/generate/commands/gentests/debug.go
rename to internal/build/cmd/generate/commands/gentests/debug.go
index 15b5eba62c..7f5174b896
--- a/internal/cmd/generate/commands/gentests/debug.go
+++ b/internal/build/cmd/generate/commands/gentests/debug.go
@@ -1,10 +1,27 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gentests
 
 import (
 	"fmt"
 	"strings"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 // DebugInfo returns information about the endpoint as a string.
diff --git a/internal/cmd/generate/commands/gentests/gen_api_registry.go b/internal/build/cmd/generate/commands/gentests/gen_api_registry.go
old mode 100755
new mode 100644
similarity index 74%
rename from internal/cmd/generate/commands/gentests/gen_api_registry.go
rename to internal/build/cmd/generate/commands/gentests/gen_api_registry.go
index 6ae2002218..a52dc21a29
--- a/internal/cmd/generate/commands/gentests/gen_api_registry.go
+++ b/internal/build/cmd/generate/commands/gentests/gen_api_registry.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 // +build ignore
 
 package main
@@ -24,7 +41,9 @@ func init() {
 	if pkgNamesEnv := os.Getenv("PACKAGE_NAMES"); pkgNamesEnv != "" {
 		pkgNames = strings.Split(pkgNamesEnv, ",")
 	} else {
-		pkgNames = []string{"github.com/elastic/go-elasticsearch/esapi"}
+		pkgNames = []string{
+			"github.com/elastic/go-elasticsearch/v7/esapi",
+		}
 	}
 
 	if _, ok := os.LookupEnv(""); ok {
diff --git a/internal/build/cmd/generate/commands/gentests/generator.go b/internal/build/cmd/generate/commands/gentests/generator.go
new file mode 100644
index 0000000000..5981562142
--- /dev/null
+++ b/internal/build/cmd/generate/commands/gentests/generator.go
@@ -0,0 +1,1294 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package gentests
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+
+	"golang.org/x/tools/imports"
+)
+
+var (
+	goruncache map[string]string
+)
+
+func init() {
+	goruncache = make(map[string]string)
+}
+
+// Generator represents the "gentests" generator.
+//
+type Generator struct {
+	b bytes.Buffer
+
+	TestSuite TestSuite
+}
+
+// Output returns the generator output.
+//
+func (g *Generator) Output() (io.Reader, error) {
+	name := g.TestSuite.Name()
+	if g.TestSuite.Type == "xpack" {
+		name = "Xpack_" + name
+	}
+
+	g.genFileHeader()
+	g.w("func Test" + name + "(t *testing.T) {\n")
+	g.genInitializeClient()
+	g.genHelpers()
+	g.genCommonSetup()
+	if g.TestSuite.Type == "xpack" {
+		g.genXPackSetup()
+	}
+	if len(g.TestSuite.Setup) > 0 {
+		g.w("// ----- Test Suite Setup --------------------------------------------------------\n")
+		g.w("testSuiteSetup := func() {\n")
+		g.genSetupTeardown(g.TestSuite.Setup)
+		g.w("}\n")
+		g.w("_ = testSuiteSetup\n")
+		g.w("// --------------------------------------------------------------------------------\n")
+		g.w("\n")
+	}
+	if len(g.TestSuite.Teardown) > 0 {
+		g.w("\t// Teardown\n")
+		g.w("\tdefer func(t *testing.T) {\n")
+		g.genSetupTeardown(g.TestSuite.Teardown)
+		g.w("\t}(t)\n")
+	}
+	for i, t := range g.TestSuite.Tests {
+		g.w("\n")
+		g.genLocationYAML(t)
+		g.w("\t" + `t.Run("` + strings.ReplaceAll(t.Name, " ", "_") + `", ` + "func(t *testing.T) {\n")
+		if !g.genSkip(t) {
+			g.w("\tdefer recoverPanic(t)\n")
+			g.w("\tcommonSetup()\n")
+			if g.TestSuite.Type == "xpack" {
+				g.w("\txpackSetup()\n")
+			}
+			if len(g.TestSuite.Setup) > 0 {
+				g.w("\ttestSuiteSetup()\n")
+			}
+			g.w("\n")
+			if len(t.Setup) > 0 {
+				g.w("\t// Test setup\n")
+				g.genSetupTeardown(t.Setup)
+			}
+			if len(t.Teardown) > 0 {
+				g.w("\t// Test teardown\n")
+				g.w("\tdefer func(t) {\n")
+				g.genSetupTeardown(t.Teardown)
+				g.w("\t}(t *testing.T)\n")
+			}
+			if len(t.Setup) > 0 || len(t.Teardown) > 0 {
+				g.w("\n")
+			}
+			g.genSteps(t)
+		}
+		g.w("\t})\n")
+		if i < len(g.TestSuite.Tests)-1 {
+			g.w("\n")
+		}
+	}
+	g.w("}\n")
+	return bytes.NewReader(g.b.Bytes()), nil
+}
+
+// OutputFormatted returns a formatted generator output.
+//
+func (g *Generator) OutputFormatted() (io.Reader, error) {
+	out, err := g.Output()
+	if err != nil {
+		return bytes.NewReader(g.b.Bytes()), err
+	}
+
+	var b bytes.Buffer
+	if _, err := io.Copy(&b, out); err != nil {
+		return bytes.NewReader(g.b.Bytes()), err
+	}
+
+	fout, err := imports.Process(
+		"",
+		g.b.Bytes(),
+		&imports.Options{
+			AllErrors:  true,
+			Comments:   true,
+			FormatOnly: false,
+			TabIndent:  true,
+			TabWidth:   1,
+		})
+	if err != nil {
+		return bytes.NewReader(b.Bytes()), err
+	}
+
+	g.b.Reset()
+	g.b.Write(fout)
+
+	return bytes.NewReader(fout), nil
+}
+
+func (g *Generator) w(s string) {
+	g.b.WriteString(s)
+}
+
+func (g *Generator) gorun(code string) (string, error) {
+	if goruncache[code] != "" {
+		return goruncache[code], nil
+	}
+
+	dir, err := ioutil.TempDir("tmp", "gorun")
+	if err != nil {
+		return "", fmt.Errorf("gorun: %s", err)
+	}
+	f, err := os.Create(filepath.Join(dir, "type_for_struct_field.go"))
+	if err != nil {
+		return "", fmt.Errorf("gorun: %s", err)
+	}
+	defer func() {
+		f.Close()
+		os.RemoveAll(dir)
+	}()
+
+	// fmt.Println(code)
+	if err := ioutil.WriteFile(f.Name(), []byte(code), 0644); err != nil {
+		return "", fmt.Errorf("gorun: %s", err)
+	}
+
+	cmd := exec.Command("go", "run", f.Name())
+	out, err := cmd.Output()
+	if err != nil {
+		if e, ok := err.(*exec.ExitError); ok {
+			return "", fmt.Errorf("gorun: %s", e.Stderr)
+		}
+		return "", fmt.Errorf("gorun: %s", err)
+	}
+
+	goruncache[code] = string(out)
+
+	return string(out), nil
+}
+
+func (g *Generator) genFileHeader() {
+	g.w("// Code generated")
+	if EsVersion != "" || GitCommit != "" || GitTag != "" {
+		g.w(" from YAML test suite version")
+		if GitCommit != "" {
+			g.w(fmt.Sprintf(" %s", GitCommit))
+			if GitTag != "" {
+				g.w(fmt.Sprintf("|%s", GitTag))
+			}
+		}
+	}
+	g.w(" -- DO NOT EDIT\n")
+	g.w("\n")
+	g.w("package esapi_test\n")
+	g.w(`
+import (
+	encjson "encoding/json"
+	encyaml "gopkg.in/yaml.v2"
+	"fmt"
+	"context"
+	"crypto/tls"
+	"net/url"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/elastic/go-elasticsearch/v7"
+	"github.com/elastic/go-elasticsearch/v7/esapi"
+	"github.com/elastic/go-elasticsearch/v7/estransport"
+)
+
+var (
+	// Prevent compilation errors for unused packages
+	_ = fmt.Printf
+	_ = encjson.NewDecoder
+	_ = encyaml.NewDecoder
+	_ = tls.Certificate{}
+	_ = url.QueryEscape
+)` + "\n")
+}
+
+func (g *Generator) genInitializeClient() {
+	g.w(`
+	cfg := elasticsearch.Config{}
+	`)
+
+	if g.TestSuite.Type == "xpack" {
+		g.w(`
+	cfg.Transport = &http.Transport{
+		TLSClientConfig: &tls.Config{
+			InsecureSkipVerify: true,
+		},
+	}` + "\n")
+	}
+
+	g.w(`
+			if os.Getenv("DEBUG") != "" {
+				cfg.Logger = &estransport.ColorLogger{
+					Output: os.Stdout,
+					// EnableRequestBody:  true,
+					EnableResponseBody: true,
+				}
+			}` + "\n")
+
+	g.w(`
+	es, eserr := elasticsearch.NewClient(cfg)
+	if eserr != nil {
+		t.Fatalf("Error creating the client: %s\n", eserr)
+	}
+
+`)
+}
+
+func (g *Generator) genHelpers() {
+	g.w(`recoverPanic := func(t *testing.T) {
+	reLocation := regexp.MustCompile("(.*_test.go:\\d+).*")
+	if rec := recover(); rec != nil {
+		var loc string
+		s := strings.Split(string(debug.Stack()), "\n")
+		for i := len(s) - 1; i >= 0; i-- {
+			if reLocation.MatchString(s[i]) {
+				loc = strings.TrimSpace(s[i])
+				break
+			}
+		}
+		t.Fatalf("Panic: %s in %s", rec, reLocation.ReplaceAllString(loc, "$1"))
+	}
+}
+_ = recoverPanic
+` + "\n")
+
+	g.w(`
+	handleResponseError := func(t *testing.T, res *esapi.Response) {
+		if res.IsError() {
+			reLocation := regexp.MustCompile("(.*_test.go:\\d+).*")
+			var loc string
+			s := strings.Split(string(debug.Stack()), "\n")
+			for i := len(s) - 1; i >= 0; i-- {
+				if reLocation.MatchString(s[i]) {
+					loc = strings.TrimSpace(s[i])
+					break
+				}
+			}
+			t.Logf("Response error: %s in %s", res, reLocation.ReplaceAllString(loc, "$1"))
+		}
+	}
+	_ = handleResponseError
+`)
+	g.w("\n\n")
+}
+
+// Reference: https://github.com/elastic/elasticsearch/blob/master/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java
+//
+func (g *Generator) genCommonSetup() {
+	g.w(`
+	// ----- Common Setup -------------------------------------------------------------
+	commonSetup := func() {
+		var res *esapi.Response
+
+		{
+			res, _ = es.Cluster.Health(es.Cluster.Health.WithWaitForNoInitializingShards(true))
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+			}
+		}
+
+		{
+			res, _ = es.Indices.DeleteDataStream(
+				[]string{"*"},
+				es.Indices.DeleteDataStream.WithExpandWildcards("all"),
+				es.Indices.DeleteDataStream.WithExpandWildcards("hidden"))
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+			}
+		}
+
+		{
+			res, _ = es.Indices.Delete(
+				[]string{"*"},
+				es.Indices.Delete.WithExpandWildcards("all"))
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+			}
+		}
+
+		{
+			var r map[string]interface{}
+			res, _ = es.Indices.GetTemplate()
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+				json.NewDecoder(res.Body).Decode(&r)
+				for templateName, _ := range r {
+					if strings.HasPrefix(templateName, ".") {
+						continue
+					}
+					if templateName == "security_audit_log" {
+						continue
+					}
+					if templateName == "logstash-index-template" {
+						continue
+					}
+					es.Indices.DeleteTemplate(templateName)
+				}
+			}
+		}
+
+		{
+			res, _ = es.Indices.DeleteIndexTemplate("*")
+			if res != nil && res.Body != nil { defer res.Body.Close() }
+		}
+
+		{
+			res, _ = es.Indices.DeleteAlias([]string{"_all"}, []string{"_all"})
+			if res != nil && res.Body != nil { defer res.Body.Close() }
+		}
+
+		{
+			var r map[string]interface{}
+			res, _ = es.Snapshot.GetRepository()
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+				json.NewDecoder(res.Body).Decode(&r)
+				for repositoryID, _ := range r {
+					var r map[string]interface{}
+					res, _ = es.Snapshot.Get(repositoryID, []string{"_all"})
+					json.NewDecoder(res.Body).Decode(&r)
+					if r["responses"] != nil {
+						for _, vv := range r["responses"].([]interface{}) {
+							for _, v := range vv.(map[string]interface{})["snapshots"].([]interface{}) {
+								snapshotID, ok := v.(map[string]interface{})["snapshot"]
+								if !ok {
+									continue
+								}
+								es.Snapshot.Delete(repositoryID, fmt.Sprintf("%s", snapshotID))
+							}
+						}
+					}
+					es.Snapshot.DeleteRepository([]string{fmt.Sprintf("%s", repositoryID)})
+				}
+			}
+		}
+
+		{
+			res, _ = es.Cluster.Health(es.Cluster.Health.WithWaitForStatus("yellow"))
+			if res != nil && res.Body != nil {
+				defer res.Body.Close()
+			}
+		}
+	}
+	_ = commonSetup
+
+	`)
+}
+
+// Reference: https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestIT.java
+// Reference: https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/integration/MlRestTestStateCleaner.java
+//
+func (g *Generator) genXPackSetup() {
+	g.w(`
+		// ----- XPack Setup -------------------------------------------------------------
+		xpackSetup := func() {
+			var res *esapi.Response
+
+			{
+				res, _ = es.Indices.DeleteDataStream([]string{"*"})
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Indices.GetTemplate()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for templateName, _ := range r {
+						if strings.HasPrefix(templateName, ".") {
+							continue
+						}
+						es.Indices.DeleteTemplate(templateName)
+					}
+				}
+			}
+
+			{
+				res, _ = es.Watcher.DeleteWatch("my_watch")
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Security.GetRole()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for k, v := range r {
+						reserved, ok := v.(map[string]interface{})["metadata"].(map[string]interface{})["_reserved"].(bool)
+						if ok && reserved {
+							continue
+						}
+						es.Security.DeleteRole(k)
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Security.GetUser()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for k, v := range r {
+						reserved, ok := v.(map[string]interface{})["metadata"].(map[string]interface{})["_reserved"].(bool)
+						if ok && reserved {
+							continue
+						}
+						es.Security.DeleteUser(k)
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Security.GetPrivileges()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for k, v := range r {
+						reserved, ok := v.(map[string]interface{})["metadata"].(map[string]interface{})["_reserved"].(bool)
+						if ok && reserved {
+							continue
+						}
+						es.Security.DeletePrivileges(k, "_all")
+					}
+				}
+			}
+
+			{
+				res, _ = es.Indices.Refresh(
+					es.Indices.Refresh.WithIndex("_all"),
+					es.Indices.Refresh.WithExpandWildcards("open,closed,hidden"))
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+				defer cancel()
+				es.ML.StopDatafeed("_all", es.ML.StopDatafeed.WithContext(ctx))
+				res, _ = es.ML.GetDatafeeds()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for _, v := range r["datafeeds"].([]interface{}) {
+						datafeed, ok := v.(map[string]interface{})
+						if ok {
+							datafeedID := datafeed["datafeed_id"].(string)
+							es.ML.DeleteDatafeed(datafeedID)
+						}
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+				defer cancel()
+				es.ML.CloseJob("_all", es.ML.CloseJob.WithContext(ctx))
+				res, _ = es.ML.GetJobs()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for _, v := range r["jobs"].([]interface{}) {
+						job, ok := v.(map[string]interface{})
+						if ok {
+							jobID := job["job_id"].(string)
+							es.ML.DeleteJob(jobID)
+						}
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Rollup.GetJobs(es.Rollup.GetJobs.WithJobID("_all"))
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for _, v := range r["jobs"].([]interface{}) {
+						job, ok := v.(map[string]interface{})["config"]
+						if ok {
+							jobID := job.(map[string]interface{})["id"].(string)
+							es.Rollup.StopJob(jobID, es.Rollup.StopJob.WithWaitForCompletion(true))
+							es.Rollup.DeleteJob(jobID)
+						}
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Tasks.List()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for _, vv := range r["nodes"].(map[string]interface{}) {
+						for _, v := range vv.(map[string]interface{})["tasks"].(map[string]interface{}) {
+							cancellable, ok := v.(map[string]interface{})["cancellable"]
+							if ok && cancellable.(bool) {
+								taskID := fmt.Sprintf("%v:%v", v.(map[string]interface{})["node"], v.(map[string]interface{})["id"])
+								ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+								defer cancel()
+								es.Tasks.Cancel(es.Tasks.Cancel.WithTaskID(taskID), es.Tasks.Cancel.WithContext(ctx))
+							}
+						}
+					}
+				}
+			}
+
+			{
+				var r map[string]interface{}
+				res, _ = es.Snapshot.GetRepository()
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+					json.NewDecoder(res.Body).Decode(&r)
+					for repositoryID, _ := range r {
+						var r map[string]interface{}
+						res, _ = es.Snapshot.Get(repositoryID, []string{"_all"})
+						json.NewDecoder(res.Body).Decode(&r)
+						for _, vv := range r["responses"].([]interface{}) {
+							for _, v := range vv.(map[string]interface{})["snapshots"].([]interface{}) {
+								snapshotID, ok := v.(map[string]interface{})["snapshot"]
+								if ok {
+									es.Snapshot.Delete(repositoryID, fmt.Sprintf("%s", snapshotID))
+								}
+							}
+						}
+						es.Snapshot.DeleteRepository([]string{fmt.Sprintf("%s", repositoryID)})
+					}
+				}
+			}
+
+			{
+				res, _ = es.Indices.Delete([]string{".ml*"})
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				res, _ = es.ILM.RemovePolicy("_all")
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				res, _ = es.Cluster.Health(es.Cluster.Health.WithWaitForStatus("yellow"))
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				res, _ = es.Security.PutUser("x_pack_rest_user", strings.NewReader(` + "`" + `{"password":"x-pack-test-password", "roles":["superuser"]}` + "`" + `), es.Security.PutUser.WithPretty())
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				res, _ = es.Indices.Refresh(
+					es.Indices.Refresh.WithIndex("_all"),
+					es.Indices.Refresh.WithExpandWildcards("open,closed,hidden"))
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				res, _ = es.Cluster.Health(es.Cluster.Health.WithWaitForStatus("yellow"))
+				if res != nil && res.Body != nil {
+					defer res.Body.Close()
+				}
+			}
+
+			{
+				var i int
+				for {
+					i++
+					var r map[string]interface{}
+					res, _ = es.Cluster.PendingTasks()
+					if res != nil && res.Body != nil {
+						defer res.Body.Close()
+						json.NewDecoder(res.Body).Decode(&r)
+						if len(r["tasks"].([]interface{})) < 1 {
+							break
+						}
+					}
+					if i > 30 {
+						break
+					}
+					time.Sleep(time.Second)
+				}
+			}
+		}
+		_ = xpackSetup
+
+	`)
+}
+
+func (g *Generator) genLocationYAML(t Test) {
+	f, err := os.Open(t.Filepath)
+	if err != nil {
+		g.w(fmt.Sprintf("// Error opening file: %s\n", err))
+	}
+
+	scanner := bufio.NewScanner(f)
+	var i int
+	for scanner.Scan() {
+		i++
+		tname := scanner.Text()
+		tname = strings.TrimRight(tname, `:`)
+		tname = strings.NewReplacer(`\"`, `"`).Replace(tname)
+		tname = strings.TrimPrefix(tname, `"`)
+		tname = strings.TrimSuffix(tname, `"`)
+
+		if tname == t.OrigName {
+			// TODO: Github URL (with proper branch/commit/etc)
+			g.w("\t// Source: " + t.Filepath + fmt.Sprintf(":%d", i) + "\n\t//\n")
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		g.w(fmt.Sprintf("// Error reading file: %s\n", err))
+	}
+}
+
+func (g *Generator) genSkip(t Test) (skipped bool) {
+	// Check the custom skip list
+	if skips, ok := skipTests[t.BaseFilename()]; ok {
+		if len(skips) < 1 {
+			g.w("\t// Skipping all tests in '" + t.BaseFilename() + "'\n")
+			g.w("\tt.SkipNow()\n\n")
+			return true
+		}
+
+		for _, skip := range skips {
+			if skip == t.OrigName {
+				g.w("\tt.SkipNow()\n\n")
+				return true
+			}
+		}
+	}
+
+	// Check the skip property coming from YAML
+	if t.Skip {
+		if t.SkipInfo != "" {
+			g.w("\tt.Skip(" + strconv.Quote(t.SkipInfo) + ")\n\n")
+			return true
+		} else {
+			g.w("\tt.SkipNow()\n\n")
+			return true
+		}
+	}
+
+	return false
+}
+
+func (g *Generator) genSetupTeardown(actions []Action) {
+	g.genVarSection(Test{})
+
+	for _, a := range actions {
+		g.genAction(a, false)
+		g.w("\n")
+	}
+}
+
+func (g *Generator) genSteps(t Test) {
+	var skipBody bool
+	if !t.Steps.ContainsAssertion() && !t.Steps.ContainsCatch() && !t.Steps.ContainsStash() {
+		skipBody = true
+	}
+	g.genVarSection(t, skipBody)
+
+	for _, step := range t.Steps {
+		switch step.(type) {
+		case Action:
+			// Generate debug info
+			var dbg strings.Builder
+			dbg.WriteString("\t\t// => " + step.(Action).Method() + "(")
+			var j int
+			for k, v := range step.(Action).Params() {
+				j++
+				dbg.WriteString(k + ": " + strings.Replace(fmt.Sprintf("%v", v), "\n", "|", -1))
+				if j < len(step.(Action).Params()) {
+					dbg.WriteString(", ")
+				}
+			}
+			dbg.WriteString(") ")
+			pad := 101 - dbg.Len()
+			if pad < 0 {
+				pad = 0
+			}
+			g.w(dbg.String() + strings.Repeat("-", pad) + "\n\t\t//\n")
+
+			// Generate the action
+			g.genAction(step.(Action), skipBody)
+			g.w("\t\t// " + strings.Repeat("-", 96) + "\n\n")
+		case Assertion:
+			// Generate debug info
+			g.w("\t\t// ~> ")
+			g.w(fmt.Sprintf("%q: ", step.(Assertion).operation))
+			g.w(strings.Replace(fmt.Sprintf("%s", step.(Assertion).payload), "\n", "|", -1))
+			g.w("\n")
+			// Generate the assertion
+			g.genAssertion(step.(Assertion))
+			g.w("\n")
+		case Stash:
+			// Generate setting the stash
+			g.genStashSet(step.(Stash))
+			g.w("\n")
+		default:
+			panic(fmt.Sprintf("Unknown step %T", step))
+		}
+	}
+}
+
+func (g *Generator) genVarSection(t Test, skipBody ...bool) {
+	g.w("\t\tvar (\n")
+	g.w("\t\t\treq esapi.Request\n")
+	g.w("\t\t\tres *esapi.Response\n")
+	g.w("\t\t\terr error\n\n")
+
+	g.w("\t\t\tstash = make(map[string]interface{}, 0)\n\n")
+
+	if (len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false)) &&
+		(t.Steps.ContainsAssertion() || t.Steps.ContainsCatch() || true) {
+		g.w("\t\t\tbody []byte\n")
+		g.w("\t\t\tmapi map[string]interface{}\n")
+		g.w("\t\t\tslic []interface{}\n")
+	}
+
+	if t.Steps.ContainsAssertion("is_false", "is_true") {
+		g.w("\n\t\t\tvalue reflect.Value\n")
+	}
+
+	g.w("\n")
+	g.w("\t\t\tassertion bool\n")
+
+	g.w("\t\t\tactual   interface{}\n")
+	g.w("\t\t\texpected interface{}\n")
+	g.w("\n")
+
+	if t.Steps.ContainsAssertion("match", "match-regexp") {
+		g.w("\n\t\t\tre *regexp.Regexp\n")
+		g.w("\t\t\tmatch bool\n")
+	}
+
+	g.w("\t\t)\n\n")
+
+	if (len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false)) &&
+		(t.Steps.ContainsAssertion() || t.Steps.ContainsCatch() || true) {
+		g.w("\t\t_ = mapi\n")
+		g.w("\t\t_ = slic\n")
+		g.w("\n")
+		g.w(`handleResponseBody := func(t *testing.T, res *esapi.Response) {
+			// Reset deserialized structures
+			mapi = make(map[string]interface{})
+			slic = make([]interface{}, 0)
+
+			var err error
+			body, err = ioutil.ReadAll(res.Body)
+			if err != nil {
+				t.Fatalf("Error reading body: %s", err)
+			}
+			res.Body.Close()
+			res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
+
+			if len(body) < 1 {
+				// FIXME: Hack to prevent EOF errors
+				return
+			}
+
+			if len(res.Header) > 0 {
+				if strings.Contains(res.Header["Content-Type"][0], "text/plain") {
+					return
+				}
+
+				if strings.Contains(res.Header["Content-Type"][0], "yaml") {
+					if strings.HasPrefix(string(body), "---\n-") {
+						if err := encyaml.NewDecoder(res.Body).Decode(&slic); err != nil {
+							t.Fatalf("Error parsing the response body: %s", err)
+						}
+					} else {
+						if err := encyaml.NewDecoder(res.Body).Decode(&mapi); err != nil {
+							t.Fatalf("Error parsing the response body: %s", err)
+						}
+					}
+					return
+				}
+			}
+
+			d := encjson.NewDecoder(res.Body)
+			d.UseNumber()
+
+			if strings.HasPrefix(string(body), "[") {
+				if err := d.Decode(&slic); err != nil {
+					t.Fatalf("Error parsing the response body: %s", err)
+				}
+			} else {
+				if err := d.Decode(&mapi); err != nil {
+					t.Fatalf("Error parsing the response body: %s", err)
+				}
+			}
+		}` + "\n")
+	}
+
+	g.w("\n")
+
+	g.w("\t\t_ = stash\n")
+
+	if t.Steps.ContainsAssertion("is_false", "is_true") {
+		g.w("\t\t_ = value\n")
+	}
+
+	g.w("\t\t_ = assertion\n")
+
+	g.w("\t\t_ = actual\n")
+	g.w("\t\t_ = expected\n")
+
+	if t.Steps.ContainsAssertion("match", "match-regexp") {
+		g.w("\n")
+		g.w("\t\t_ = re\n")
+		g.w("\t\t_ = match\n")
+	}
+
+	g.w("\n")
+}
+
+func (g *Generator) genAction(a Action, skipBody ...bool) {
+	varDetection := regexp.MustCompile(".*(\\$\\{(\\w+)\\}).*")
+
+	// Initialize the request
+	g.w("\t\treq = esapi." + a.Request() + "{\n")
+
+	// Pass the parameters
+	for k, v := range a.Params() {
+		// fmt.Printf("%s.%s: <%T> %v\n", a.Request(), k, v, v)
+
+		if strings.HasPrefix(fmt.Sprintf("%s", v), "$") {
+			v = `stash[` + strconv.Quote(strings.ReplaceAll(strings.ReplaceAll(fmt.Sprintf("%s", v), "{", ""), "}", "")) + `]`
+		}
+
+		switch v.(type) {
+		case bool:
+			g.w("\t\t\t" + k + ": ")
+
+			typ, ok := apiRegistry[a.Request()][k]
+			if !ok {
+				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
+			}
+
+			switch typ {
+			case "bool":
+				g.w(strconv.FormatBool(v.(bool)))
+			case "*bool":
+				g.w(`esapi.BoolPtr(` + strconv.FormatBool(v.(bool)) + `)`)
+			case "string":
+				g.w(`"` + strconv.FormatBool(v.(bool)) + `"`)
+			case "[]string":
+				// TODO: Listify
+				g.w(`[]string{"` + strconv.FormatBool(v.(bool)) + `"}`)
+			default:
+				g.w(strconv.FormatBool(v.(bool)))
+			}
+			g.w(",\n")
+
+		case string:
+			if k == "Body" {
+				g.w("\t\t\t" + k + ": ")
+				body := v.(string)
+
+				if varDetection.MatchString(body) {
+					g.w("strings.NewReader(strings.NewReplacer(")
+
+					matchs := varDetection.FindAllStringSubmatch(body, -1)
+					for _, match := range matchs {
+						bodyVar := match[1]
+						stashVar := fmt.Sprintf(`stash["$%s"].(string)`, match[2])
+
+						g.w(fmt.Sprintf("`%s`, %s", bodyVar, stashVar))
+					}
+					g.w(").Replace(`" + body + "`))")
+				} else {
+					if !strings.HasSuffix(body, "\n") {
+						body = body + "\n"
+					}
+					g.w("strings.NewReader(`" + body + "`)")
+				}
+
+			} else {
+				g.w("\t\t\t" + k + ": ")
+				// TODO: Handle comma separated strings as lists
+
+				// fmt.Printf("%s: %#v\n", a.Request(), apiRegistry[a.Request()])
+				// fmt.Printf("%s: %#v\n", k, apiRegistry[a.Request()][k])
+				typ, ok := apiRegistry[a.Request()][k]
+				if !ok {
+					panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
+				}
+
+				var value string
+				if strings.HasPrefix(v.(string), "stash[") {
+					switch typ {
+					case "bool":
+						value = `fmt.Sprintf("%v", ` + v.(string) + `)`
+					case "string":
+						value = fmt.Sprintf("%s.(string)", v)
+					case "[]string":
+						// TODO: Comma-separated list => Quoted list
+						value = fmt.Sprintf(`[]string{%s.(string)}`, v)
+					case "int":
+						value = `func() int {
+				switch ` + v.(string) + `.(type) {
+				case int:
+					return ` + v.(string) + `.(int)
+				case float64:
+					return int(` + v.(string) + `.(float64))
+				}
+				case json.Number:
+					v, _ := ` + v.(string) + `.(encjson.Number).Int64()
+					vv := int(v)
+					return vv
+				panic(fmt.Sprintf(` + "`" + `Unexpected type %T for ` + v.(string) + "`" + `, ` + v.(string) + `))
+			}()`
+					case "*int":
+						value = `func() *int {
+				switch ` + v.(string) + `.(type) {
+				case int:
+					v := ` + v.(string) + `.(int)
+					return &v
+				case float64:
+					v := int(` + v.(string) + `.(float64))
+					return &v
+				case json.Number:
+					v, _ := ` + v.(string) + `.(encjson.Number).Int64()
+					vv := int(v)
+					return &vv
+				}
+				panic(fmt.Sprintf(` + "`" + `Unexpected type %T for ` + v.(string) + "`" + `, ` + v.(string) + `))
+			}()`
+					case "time.Duration":
+						value = `fmt.Sprintf("%d", ` + v.(string) + `)`
+					default:
+						panic(fmt.Sprintf("Unexpected type %q for value %v", typ, v))
+					}
+				} else {
+					switch typ {
+					case "[]string":
+						value = `[]string{` + fmt.Sprintf("%q", v) + `}`
+					case "time.Duration":
+						// re := regexp.MustCompile("^(\\d+).*")
+						// value = re.ReplaceAllString(fmt.Sprintf("%s", v), "$1")
+						inputValue := v.(string)
+						if strings.HasSuffix(inputValue, "d") {
+							inputValue = inputValue[:len(inputValue)-1]
+							numericValue, err := strconv.Atoi(inputValue)
+							if err != nil {
+								panic(fmt.Sprintf("Cannot convert duration [%s]: %s", inputValue, err))
+							}
+							// Convert to hours
+							inputValue = fmt.Sprintf("%dh", numericValue*24)
+						}
+
+						dur, err := time.ParseDuration(inputValue)
+						if err != nil {
+							panic(fmt.Sprintf("Cannot parse duration [%s]: %s", v, err))
+						}
+						value = fmt.Sprintf("%d", dur.Nanoseconds())
+					default:
+						if strings.HasSuffix(k, "ID") {
+							value = fmt.Sprintf("url.QueryEscape(%q)", v)
+						} else {
+							value = fmt.Sprintf("%q", v)
+						}
+
+					}
+				}
+				g.w(value)
+			}
+			g.w(",\n")
+
+		case int, *int, float64:
+			g.w("\t\t\t" + k + ": ")
+
+			typ, ok := apiRegistry[a.Request()][k]
+			if !ok {
+				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
+			}
+
+			var value string
+			switch typ {
+			case "string":
+				value = `"` + fmt.Sprintf("%d", v) + `"`
+			case "[]string":
+				value = `[]string{"` + fmt.Sprintf("%d", v) + `"}`
+			case "time.Duration":
+				re := regexp.MustCompile("^(\\d+).*")
+				value = re.ReplaceAllString(fmt.Sprintf("%d", v), "$1")
+			case "*int":
+				switch v.(type) {
+				case int:
+					g.w(`esapi.IntPtr(` + fmt.Sprintf("%d", v) + `)`)
+				case float64:
+					if vv, ok := v.(float64); ok {
+						g.w(`esapi.IntPtr(` + fmt.Sprintf("%d", int(vv)) + `)`)
+					}
+				default:
+					panic(fmt.Sprintf("Unexpected type [%T] for [%s]", v, k))
+				}
+			default:
+				value = fmt.Sprintf("%v", v)
+			}
+			g.w(value)
+			g.w(",\n")
+
+		case []interface{}:
+			g.w("\t\t\t" + k + ": ")
+
+			typ, ok := apiRegistry[a.Request()][k]
+			if !ok {
+				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
+			}
+
+			switch typ {
+			case "string":
+				switch v.(type) {
+				case string:
+					g.w("`" + v.(string) + "`")
+				case []interface{}:
+					vvv := make([]string, 0)
+					for _, vv := range v.([]interface{}) {
+						vvv = append(vvv, fmt.Sprintf("%s", vv))
+					}
+					g.w("`" + strings.Join(vvv, ",") + "`")
+				default:
+					panic(fmt.Sprintf("<%s> %s{}.%s: unexpected value <%T> %#v", typ, a.Request(), k, v, v))
+				}
+			case "[]string":
+				qv := make([]string, 0)
+				for _, vv := range v.([]interface{}) {
+					// TODO: Check type
+					qv = append(qv, fmt.Sprintf("%q", vv.(string)))
+				}
+				g.w(`[]string{` + strings.Join(qv, ",") + `}`)
+			case "io.Reader":
+				// Serialize Bulk payloads ...
+				if k == "Body" {
+					var b strings.Builder
+					for _, vv := range v.([]interface{}) {
+						switch vv.(type) {
+						case string:
+							b.WriteString(vv.(string))
+						default:
+							j, err := json.Marshal(convert(vv))
+							if err != nil {
+								panic(fmt.Sprintf("%s{}.%s: %s (%s)", a.Request(), k, err, v))
+							}
+							b.WriteString(string(j))
+						}
+						b.WriteString("\n")
+					}
+					b.WriteString("\n")
+					g.w("\t\tstrings.NewReader(`" + b.String() + "`)")
+					// ... or just convert the value to JSON
+				} else {
+					j, err := json.Marshal(convert(v))
+					if err != nil {
+						panic(fmt.Sprintf("%s{}.%s: %s (%s)", a.Request(), k, err, v))
+					}
+					g.w("\t\tstrings.NewReader(`" + fmt.Sprintf("%s", j) + "`)")
+				}
+			}
+			g.w(",\n")
+
+		case map[interface{}]interface{}:
+			g.w("\t\t\t" + k + ": ")
+			// vv := unstash(convert(v).(map[string]interface{}))
+			// fmt.Println(vv)
+			j, err := json.Marshal(convert(v))
+			if err != nil {
+				panic(fmt.Sprintf("JSON parse error: %s; %s", err, v))
+			} else {
+				// Unstash values
+				reStash := regexp.MustCompile(`("\$[^"]+")`)
+				j = reStash.ReplaceAll(j, []byte("` + strconv.Quote(fmt.Sprintf(\"%v\", stash[$1])) + `"))
+
+				g.w("\t\tstrings.NewReader(`" + fmt.Sprintf("%s", j) + "`)")
+				g.w(",\n")
+			}
+
+		default:
+			g.w(fmt.Sprintf("\t\t// TODO: %s (%v)\n", k, v))
+		}
+	}
+
+	if len(a.headers) > 0 {
+		if strings.Contains(a.headers["Accept"], "yaml") && strings.HasPrefix(a.Request(), "Cat") {
+			g.w("\t\t" + `Format: "yaml",` + "\n")
+		}
+
+		g.w("\t\tHeader: http.Header{\n")
+		for name, value := range a.headers {
+
+			if name == "Content-Type" && value == "application/json" {
+				continue
+			}
+
+			if name == "Authorization" {
+				auth_fields := strings.Split(value, " ")
+				auth_name := auth_fields[0]
+				auth_value := auth_fields[1]
+				if strings.HasPrefix(auth_value, "$") {
+					auth_value = `fmt.Sprintf("%s", stash["` + strings.ReplaceAll(strings.ReplaceAll(auth_value, "{", ""), "}", "") + `"])`
+				} else {
+					auth_value = `"` + auth_value + `"`
+				}
+				g.w("\t\t\t" + `"Authorization": []string{"` + auth_name + ` " + ` + auth_value + `},` + "\n")
+
+			} else {
+				g.w("\t\t\t\"" + name + "\": []string{\"" + value + "\"},\n")
+			}
+
+		}
+		g.w("\t\t},\n")
+	}
+
+	g.w("\t\t}\n\n")
+
+	// Get response
+	g.w("\t\tres, err = req.Do(context.Background(), es)\n")
+
+	g.w(`		if err != nil {
+			t.Fatalf("ERROR: %s", err)
+		}
+		defer res.Body.Close()
+	`)
+
+	g.w("\n\n")
+
+	if len(a.catch) < 1 {
+		// Handle error responses
+		g.w(`		handleResponseError(t, res)` + "\n")
+	} else {
+		// TODO: Test catch
+	}
+
+	if len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false) {
+		// Read and parse the body
+		g.w(`		handleResponseBody(t, res)` + "\n")
+	}
+}
+
+func (g *Generator) genAssertion(a Assertion) {
+	g.w(a.Condition())
+	g.w(a.Error() + "\n")
+	g.w("}\n") // Close the condition
+}
+
+func (g *Generator) genStashSet(s Stash) {
+	g.w(fmt.Sprintf("// Set %q\n", s.Key()))
+
+	var stash string
+	value := s.ExpandedValue()
+
+	switch {
+	case strings.Contains(value, "_arbitrary_key_"):
+		key := strings.Trim(s.FirstValue(), "._arbitrary_key_")
+
+		stash = `for k, _ := range mapi["` + key + `"].(map[string]interface{}) {
+				stash["` + s.Key() + `"] = k
+			}
+		`
+	case strings.HasPrefix(value, `mapi["#`):
+		switch {
+		case strings.HasPrefix(value, `mapi["#base64EncodeCredentials`):
+			i, j := strings.Index(value, "("), strings.Index(value, ")")
+			values := strings.Split(value[i+1:j], ",")
+			value = `base64.StdEncoding.EncodeToString([]byte(`
+			value += `strings.Join([]string{`
+			for n, v := range values {
+				value += `mapi["` + v + `"].(string)`
+				if n < len(values)-1 {
+					value += ","
+				}
+			}
+			value += `}, ":")`
+			value += `))`
+			stash = fmt.Sprintf("stash[%q] = %s\n", s.Key(), value)
+		default:
+			panic(fmt.Sprintf("Unknown transformation: %s", value))
+		}
+	default:
+		stash = fmt.Sprintf("stash[%q] = %s\n", s.Key(), value)
+	}
+
+	g.w(stash)
+}
+
+func convert(i interface{}) interface{} {
+	switch x := i.(type) {
+	case map[interface{}]interface{}:
+		m2 := map[string]interface{}{}
+		for k, v := range x {
+			var ks string
+			switch k.(type) {
+			case string:
+				ks = k.(string)
+			case int:
+				ks = fmt.Sprintf("%d", k)
+			default:
+				ks = fmt.Sprintf("%v", k)
+			}
+			m2[ks] = convert(v)
+		}
+		return m2
+	case []interface{}:
+		for i, v := range x {
+			x[i] = convert(v)
+		}
+	}
+	return i
+}
diff --git a/internal/cmd/generate/commands/gentests/model.go b/internal/build/cmd/generate/commands/gentests/model.go
old mode 100755
new mode 100644
similarity index 79%
rename from internal/cmd/generate/commands/gentests/model.go
rename to internal/build/cmd/generate/commands/gentests/model.go
index 52ae596c01..c0334d785f
--- a/internal/cmd/generate/commands/gentests/model.go
+++ b/internal/build/cmd/generate/commands/gentests/model.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gentests
 
 import (
@@ -9,11 +26,12 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
 )
 
 var reFilename = regexp.MustCompile(`\d*_?(.+)\.ya?ml`)
 var reNumber = regexp.MustCompile(`^\d+$`)
+var reBaseFilename = regexp.MustCompile(`rest-api-spec/test/\w+/(.*$)`)
 
 // TestPayload represents a single raw section (`---`) from the YAML file.
 //
@@ -29,6 +47,7 @@ type TestSuite struct {
 	Filepath string
 	Skip     bool
 	SkipInfo string
+	Type     string
 
 	Setup    []Action
 	Teardown []Action
@@ -92,25 +111,34 @@ func NewTestSuite(fpath string, payloads []TestPayload) TestSuite {
 		Filepath: fpath,
 	}
 
+	if strings.Contains(fpath, "platinum") {
+		ts.Type = "xpack"
+	}
+	if ts.Type == "" {
+		ts.Type = "free"
+	}
+
 	for _, payload := range payloads {
 		sec_keys := utils.MapKeys(payload.Payload)
 		switch {
-		case len(sec_keys) == 1 && sec_keys[0] == "setup":
-			for _, v := range payload.Payload.(map[interface{}]interface{}) {
-				for _, vv := range v.([]interface{}) {
-					for k, vvv := range vv.(map[interface{}]interface{}) {
-						if k == "do" {
-							ts.Setup = append(ts.Setup, NewAction(vvv))
+		case len(sec_keys) > 0 && strings.Contains(strings.Join(sec_keys, ","), "setup") || strings.Contains(strings.Join(sec_keys, ","), "teardown"):
+			for k, v := range payload.Payload.(map[interface{}]interface{}) {
+				switch k {
+				case "setup":
+					for _, vv := range v.([]interface{}) {
+						for k, vvv := range vv.(map[interface{}]interface{}) {
+							if k == "do" {
+								ts.Setup = append(ts.Setup, NewAction(vvv))
+							}
 						}
-						// TODO: Handle skip in setup, eg. indices.get_mapping/10_basic.yml
 					}
-				}
-			}
-		case len(sec_keys) == 1 && sec_keys[0] == "teardown":
-			for _, v := range payload.Payload.(map[interface{}]interface{}) {
-				for _, vv := range v.([]interface{}) {
-					for _, vvv := range vv.(map[interface{}]interface{}) {
-						ts.Teardown = append(ts.Teardown, NewAction(vvv))
+				case "teardown":
+					for _, vv := range v.([]interface{}) {
+						for k, vvv := range vv.(map[interface{}]interface{}) {
+							if k == "do" {
+								ts.Teardown = append(ts.Teardown, NewAction(vvv))
+							}
+						}
 					}
 				}
 			}
@@ -161,6 +189,16 @@ func NewTestSuite(fpath string, payloads []TestPayload) TestSuite {
 						for _, vvv := range vv.(map[interface{}]interface{}) {
 							steps = append(steps, NewStash(vvv))
 						}
+					case "transform_and_set":
+						for _, vvv := range vv.(map[interface{}]interface{}) {
+							// NOTE: `set_and_transform` has flipped ordering of key and value, compared to `set`
+							key := utils.MapValues(vvv)[0]
+							val := utils.MapKeys(vvv)[0]
+							payload := make(map[interface{}]interface{})
+							payload[key] = val
+							// fmt.Println(payload)
+							steps = append(steps, NewStash(payload))
+						}
 					case "do":
 						for _, vvv := range vv.(map[interface{}]interface{}) {
 							steps = append(steps, NewAction(vvv))
@@ -174,7 +212,7 @@ func NewTestSuite(fpath string, payloads []TestPayload) TestSuite {
 				}
 
 				if !ts.Skip {
-					t.Name = strings.Replace(k.(string), `"`, `'`, -1)
+					t.Name = strings.ReplaceAll(k.(string), `"`, `'`)
 					t.Filepath = payload.Filepath
 					t.OrigName = k.(string)
 					t.Steps = steps
@@ -206,8 +244,8 @@ func NewAction(payload interface{}) Action {
 		switch k {
 		case "catch":
 			a.catch = v.(string)
-		case "warnings":
-			// TODO
+		case "warnings", "allowed_warnings", "allowed_warnings_regex", "node_selector", "arbitrary_key":
+			continue
 		case "headers":
 			for kk, vv := range v.(map[interface{}]interface{}) {
 				a.headers[kk.(string)] = vv.(string)
@@ -245,13 +283,18 @@ func (ts TestSuite) Name() string {
 	for _, v := range strings.Split(bname, "_") {
 		b.WriteString(strings.Title(v))
 	}
-	return b.String()
+	return strings.ReplaceAll(b.String(), "-", "")
 }
 
 // Filename returns a suitable filename for the test suite.
 //
 func (ts TestSuite) Filename() string {
 	var b strings.Builder
+
+	if ts.Type == "xpack" {
+		b.WriteString("xpack_")
+	}
+
 	b.WriteString(strings.ToLower(strings.Replace(ts.Dir, ".", "_", -1)))
 	b.WriteString("__")
 
@@ -267,14 +310,14 @@ func (ts TestSuite) SkipEsVersion(minmax string) bool {
 	return skipVersion(minmax)
 }
 
-// BaseFilename returns the original filename in form of `foo/10_bar.yml`.
+// BaseFilename extracts and returns the test filename in form of `foo/bar/10_qux.yml`.
 //
 func (t Test) BaseFilename() string {
-	parts := strings.Split(t.Filepath, string(filepath.Separator))
-	if len(parts) < 2 {
-		return ""
+	parts := reBaseFilename.FindStringSubmatch(t.Filepath)
+	if len(parts) < 1 {
+		panic(fmt.Sprintf("Unexpected parts for path [%s]: %s", t.Filepath, parts))
 	}
-	return strings.Join(parts[len(parts)-2:], string(filepath.Separator))
+	return strings.TrimPrefix(parts[1], string(filepath.Separator))
 }
 
 // SkipEsVersion returns true if the test should be skipped.
@@ -340,13 +383,18 @@ func (s Steps) ContainsStash(keys ...string) bool {
 // Method returns the API method name for the action.
 //
 func (a Action) Method() string {
-	return strings.Title(a.method)
+	return utils.NameToGo(a.method)
 }
 
 // Request returns the API request name for the action.
 //
 func (a Action) Request() string {
-	return utils.NameToGo(strings.Replace(strings.Title(a.method), ".", "", -1)) + "Request"
+	var rParts []string
+	parts := strings.Split(a.method, ".")
+	for _, p := range parts {
+		rParts = append(rParts, utils.NameToGo(p))
+	}
+	return strings.Join(rParts, "") + "Request"
 }
 
 // Params returns a map of parameters for the action.
@@ -364,7 +412,7 @@ func (a Action) Params() map[string]interface{} {
 			// TODO: Properly handle ignoring status codes
 			continue
 		default:
-			kk = utils.NameToGo(k.(string))
+			kk = utils.NameToGo(k.(string), utils.APIToGo(a.method))
 		}
 		switch v.(type) {
 		case bool:
@@ -613,13 +661,31 @@ default:
 						`fmt.Sprintf("%v", ` + expected + `)` +
 						" {\n"
 				case int, float64:
+					// Date range special case
+					// From & to are set in yaml tests as integer
+					// but ES returns a scientific notation float
+					var specialCase string
+					if strings.HasSuffix(key, "from") || strings.HasSuffix(key, "to") {
+						specialCase = `else if floatValue, err := actual.(encjson.Number).Float64(); err == nil {
+							actual = fmt.Sprintf("%d", int(floatValue))
+						} `
+					}
+
 					r := strings.NewReplacer(`"`, "", `\`, "")
 					rkey := r.Replace(key)
 					output += `		if ` + nilGuard + ` { t.Error("Expected [` + rkey + `] to not be nil") }
-						actual = ` + escape(subject) + `.(encjson.Number).String()
-						// TEMP: Hack to prevent 1.0 != 1 errors
-						actual = strings.TrimSuffix(actual.(string), ".0")
+						actual = ` + escape(subject) + `
+						if intValue, ok := actual.(int); ok {
+							actual = fmt.Sprint(intValue)
+						}` + specialCase + `else {
+							actual = actual.(encjson.Number).String()
+						}
 						expected = ` + expected + `
+						// TEMP: Hack to prevent 1.0 != 1 errors
+						if strings.HasSuffix(actual.(string), ".0") {
+							actual = strings.TrimSuffix(actual.(string), ".0")
+							expected = strings.TrimSuffix(` + strconv.Quote(expected) + `, ".0")
+						}
 						assertion = fmt.Sprintf("%v", actual) == fmt.Sprintf("%v", expected)
 					if !assertion {
 						t.Logf("%v != %v", actual, expected)` + "\n"
@@ -629,25 +695,31 @@ default:
 					output += `		if ` +
 						nilGuard +
 						" || \n" +
-						`fmt.Sprintf("%s", ` + escape(subject) + `) != `
+						`strings.TrimSpace(fmt.Sprintf("%s", ` + escape(subject) + `)) != `
 					if strings.HasPrefix(expected, "$") {
-						output += `fmt.Sprintf("%s", ` + `stash["` + expected + `"]` + `)`
+						// Remove brackets if we compare to a stashed value replaced in the body.
+						expected = strings.NewReplacer("{", "", "}", "").Replace(expected)
+						output += `strings.TrimSpace(fmt.Sprintf("%s", ` + `stash["` + expected + `"]` + `))`
 					} else {
-						output += `fmt.Sprintf("%s", ` + strconv.Quote(expected) + `)`
+						output += `strings.TrimSpace(fmt.Sprintf("%s", ` + strconv.Quote(expected) + `))`
 					}
 					output += " {\n"
 
 				// --------------------------------------------------------------------------------
 				case map[interface{}]interface{}, map[string]interface{}:
+					// We cannot reliably serialize to json and compare the json outputs: YAML responses are parsed as
+					// a map[interface{}]interface{} that encoding/json fails to marshall
+					// See https://play.golang.org/p/jhcXwg5dIrn
 					expectedPayload := fmt.Sprintf("%#v", val)
-					expectedPayload = strings.Replace(expectedPayload, "map[interface {}]interface {}", "map[string]interface {}", -1)
-					output = `		actual, _ = encjson.Marshal(` + escape(subject) + `)
-				expected, _ = encjson.Marshal(` + expectedPayload + `)
-				if fmt.Sprintf("%s", actual) != fmt.Sprintf("%s", expected) {` + "\n"
+					expectedPayload = strings.ReplaceAll(expectedPayload, "map[interface {}]interface {}", "map[string]interface {}")
+					output = `		actual = fmt.Sprintf("%v",` + escape(subject) + `)
+				expected = fmt.Sprintf("%v",` + expectedPayload + `)
+				if actual != expected {` + "\n"
 
 				// --------------------------------------------------------------------------------
 				case []interface{}:
 					expectedPayload := fmt.Sprintf("%#v", val)
+					expectedPayload = strings.ReplaceAll(expectedPayload, "map[interface {}]interface {}", "map[string]interface {}")
 					output = `		actual, _ = encjson.Marshal(` + escape(subject) + `)
 				expected, _ = encjson.Marshal(` + expectedPayload + `)
 				if fmt.Sprintf("%s", actual) != fmt.Sprintf("%s", expected) {` + "\n"
@@ -744,9 +816,20 @@ func (s Stash) Key() string {
 	return fmt.Sprintf("$%s", vals[0])
 }
 
-// Value returns the stash value as a string.
+// Value return the stash value as a string.
+//
+func (s Stash) FirstValue() string {
+	vals := utils.MapKeys(s.payload)
+	if len(vals) < 1 {
+		return ""
+	}
+
+	return vals[0]
+}
+
+// ExpandedValue returns the stash value in a container as a string.
 //
-func (s Stash) Value() string {
+func (s Stash) ExpandedValue() string {
 	vals := utils.MapKeys(s.payload)
 	if len(vals) < 1 {
 		return ""
@@ -803,9 +886,15 @@ func expand(s string, format ...string) string {
 					b.WriteString(`.(map[string]interface{})`)
 				}
 			}
-			b.WriteString(`["`)
-			b.WriteString(strings.Trim(v, `"`)) // Remove the quotes from keys
-			b.WriteString(`"]`)
+			b.WriteString("[")
+			if strings.HasPrefix(v, "$") {
+				b.WriteString(fmt.Sprintf(`stash["%s"].(string)`, strings.Trim(v, `"`))) // Remove the quotes from keys
+			} else {
+				b.WriteString(`"`)
+				b.WriteString(strings.Trim(v, `"`)) // Remove the quotes from keys
+				b.WriteString(`"`)
+			}
+			b.WriteString("]")
 		}
 
 	}
@@ -819,7 +908,16 @@ func catchnil(input string) string {
 
 	parts := strings.Split(strings.Replace(input, `\.`, `_~_|_~_`, -1), ".")
 	for i := range parts {
-		output += strings.Join(parts[:i+1], ".") + " == nil"
+		// Skip casting for runtime stash variable replacement nil escape
+		if parts[i] == "(string)]" {
+			continue
+		}
+
+		part := parts[:i+1]
+		if strings.Contains(parts[i], "$") {
+			part = append(part, parts[i+1])
+		}
+		output += strings.Join(part, ".") + " == nil"
 		if i+1 < len(parts) {
 			output += " ||\n\t\t"
 		}
diff --git a/internal/cmd/generate/commands/gentests/patches.go b/internal/build/cmd/generate/commands/gentests/patches.go
old mode 100755
new mode 100644
similarity index 62%
rename from internal/cmd/generate/commands/gentests/patches.go
rename to internal/build/cmd/generate/commands/gentests/patches.go
index cf14e6d5d9..6840547dc0
--- a/internal/cmd/generate/commands/gentests/patches.go
+++ b/internal/build/cmd/generate/commands/gentests/patches.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package gentests
 
 import (
diff --git a/internal/build/cmd/generate/commands/gentests/skips.go b/internal/build/cmd/generate/commands/gentests/skips.go
new file mode 100644
index 0000000000..b8a4ca0a0e
--- /dev/null
+++ b/internal/build/cmd/generate/commands/gentests/skips.go
@@ -0,0 +1,348 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package gentests
+
+import (
+	"fmt"
+  "strings"
+
+	"gopkg.in/yaml.v2"
+)
+
+var skipTests map[string][]string
+
+func init() {
+	err := yaml.NewDecoder(strings.NewReader(skipTestsYAML)).Decode(&skipTests)
+	if err != nil {
+		panic(fmt.Sprintf("ERROR: %v", err))
+	}
+}
+
+var skipFiles = []string{
+	"update/85_fields_meta.yml",            // Uses non-existing API property
+	"update/86_fields_meta_with_types.yml", // --||--
+
+	"ml/jobs_get_result_buckets.yml",    // Passes string value to int variable
+	"ml/jobs_get_result_categories.yml", // --||--
+	"ml/set_upgrade_mode.yml",           // --||--
+
+	"ml/evaluate_data_frame.yml", // Floats as map keys
+
+	"watcher/stats/10_basic.yml", // Sets "emit_stacktraces" as string ("true"), not bool
+	
+	"search.highlight/20_fvh.yml", // bad backslash
+}
+
+// TODO: Comments into descriptions for `Skip()`
+//
+var skipTestsYAML = `
+---
+# Cannot distinguish between missing value for refresh and an empty string
+bulk/50_refresh.yml:
+  - refresh=empty string immediately makes changes are visible in search
+bulk/51_refresh_with_types.yml:
+  - refresh=empty string immediately makes changes are visible in search
+create/60_refresh.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+create/61_refresh_with_types.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+delete/50_refresh.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+delete/51_refresh_with_types.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+index/60_refresh.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+index/61_refresh_with_types.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+update/60_refresh.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+update/61_refresh_with_types.yml:
+  - When refresh url parameter is an empty string that means "refresh immediately"
+
+# Stash in value
+cluster.reroute/11_explain.yml:
+nodes.info/30_settings.yml:
+nodes.stats/20_response_filtering.yml:
+nodes.stats/30_discovery.yml:
+  - Discovery stats
+nodes.discovery/30_discovery.yml:
+  - Discovery stats
+
+# Arbitrary key
+indices.shrink/10_basic.yml:
+indices.shrink/20_source_mapping.yml:
+indices.shrink/30_copy_settings.yml:
+indices.split/30_copy_settings.yml:
+nodes.info/10_basic.yml:
+nodes.reload_secure_settings/10_basic.yml:
+nodes.stats/50_indexing_pressure.yml:
+nodes.stats/40_store_stats.yml:
+  - Store stats
+
+# Parsed response is YAML: value is map[interface {}]interface {}, not map[string]interface {}
+cat.aliases/20_headers.yml:
+  - Simple alias with yaml body through Accept header
+
+# Incorrect int instead of float in match (aggregations.date_range.buckets.0.from: 1000000); TODO: PR
+search.aggregation/40_range.yml:
+  - Date range
+
+# Mismatch in number parsing, 8623000 != 8.623e+06
+search.aggregation/340_geo_distance.yml:
+  - avg_bucket
+
+# Tries to match on "Cluster Get Settings" output, but that's an empty map
+search/320_disallow_queries.yml:
+
+# No support for headers per request yet
+tasks.list/10_basic.yml:
+  - tasks_list headers
+
+# Node Selector feature not implemented
+cat.aliases/10_basic.yml:
+  - "Help (pre 7.4.0)"
+  - "Simple alias (pre 7.4.0)"
+  - "Complex alias (pre 7.4.0)"
+  - "Column headers (pre 7.4.0)"
+  - "Alias against closed index (pre 7.4.0)"
+
+indices.put_mapping/10_basic.yml:
+  - "Put mappings with explicit _doc type bwc"
+
+# Test fails with: [400 Bad Request] illegal_argument_exception, "template [test] has index patterns [test-*] matching patterns from existing index templates [test2,test] with patterns (test2 => [test-*],test => [test-*, test2-*]), use index templates (/_index_template) instead"
+test/indices.put_template/10_basic.yml:
+
+# Incompatible regex
+cat.templates/10_basic.yml:
+  - "Sort templates"
+  - "Multiple template"
+
+# Missing test setup
+cluster.voting_config_exclusions/10_basic.yml:
+  - "Add voting config exclusion by unknown node name"
+
+# Not relevant
+search/issue4895.yml:
+search/issue9606.yml:
+
+# Test doesn't work on 7.x
+indices.data_stream/10_basic.yml:
+  - "Create data stream with invalid name"
+
+# FIXME
+bulk/80_cas.yml:
+bulk/81_cas_with_types.yml:
+
+# ----- X-Pack ----------------------------------------------------------------
+
+# Float "3.0" decoded as "3" by gopkg.in/yaml.v2
+analytics/top_metrics.yml:
+  - sort by double field
+  - sort by numeric script
+  - sort by scaled float field
+
+runtime_fields/30_double.yml:
+  - docvalue_fields
+  - fetch fields
+
+# Stash in body
+api_key/10_basic.yml:
+  - Test invalidate api keys
+api_key/11_invalidation.yml:
+  - Test invalidate api key by username
+rollup/put_job.yml:
+  - Test put job with templates
+
+# Incorrect syntax for stash, "${user1_key_id}"
+api_key/11_invalidation.yml:
+  - Test invalidate api key by username
+
+# Incorrect syntax for stash
+api_key/20_query.yml:
+  - Test query api key
+
+# Changing password locks out tests
+change_password/10_basic.yml:
+  - Test user changing their own password
+  - Test changing users password with prehashed password
+
+# Missing refreshes in the test
+data_frame/transforms_start_stop.yml:
+ml/index_layout.yml:
+
+# This test suite keeps failing too often: disable it altogether
+ml/data_frame_analytics_crud.yml:
+
+# More QA tests than API tests
+data_frame/transforms_stats.yml:
+  - Test get multiple transform stats
+  - Test get transform stats on missing transform
+  - Test get multiple transform stats where one does not have a task
+
+# Invalid license makes subsequent tests fail
+license/20_put_license.yml:
+
+# Test tries to match on map from body, but Go keys are not sorted
+ml/jobs_crud.yml:
+  - Test job with rules
+  - Test update job
+ml/data_frame_analytics_crud.yml:
+  - Test put classification given deprecated maximum_number_trees
+  - Test put valid config with default outlier detection
+  - Test put valid config with custom outlier detection
+
+# Test gets stuck every time
+ml/jobs_get_stats.yml:
+
+# # status_exception, Cannot process data because job [post-data-job] does not have a corresponding autodetect process
+# # resource_already_exists_exception, task with id {job-post-data-job} already exist
+# ml/post_data.yml:
+
+# Possible bad test setup, Cannot open job [start-stop-datafeed-job] because it has already been opened
+# resource_already_exists_exception, task with id {job-start-stop-datafeed-job-foo-2} already exist
+ml/start_stop_datafeed.yml:
+  - Test start datafeed when persistent task allocation disabled
+
+# Test uses "y" as a property name, which is parsed as 'true' in the Go YAML library;
+# see https://yaml.org/type/bool.html
+ml/explain_data_frame_analytics.yml:
+  - Test empty data frame given body
+  - Test non-empty data frame given body
+
+# Test uses "n" as a property name, which is parsed as 'false' in the Go YAML library;
+search.aggregation/10_histogram.yml:
+
+# Indexing step doesn't appear to work (getting total.hits=0)
+monitoring/bulk/10_basic.yml:
+  - Bulk indexing of monitoring data on closed indices should throw an export exception
+# Indexing step doesn't appear to work (getting total.hits=0)
+monitoring/bulk/20_privileges.yml:
+  - Monitoring Bulk API
+
+# Test tries to match on whole body, but map keys are unstable in Go
+rollup/security_tests.yml:
+
+# Test tries to match on map key, but map keys are unstable in Go
+ml/data_frame_analytics_crud.yml:
+  - Test put valid config with default outlier detection, query, and filter
+  - Test put valid config with default outlier detection
+  - Test put valid config with custom outlier detection
+  - Test put regression given valid
+  - Test put with description
+  - Test max model memory limit
+  - Test put classification given valid
+  - Test put classification given deprecated maximum_number_trees
+
+# TEMPORARY: Missing 'body: { indices: "test_index" }' payload, TODO: PR
+snapshot/10_basic.yml:
+  - Create a source only snapshot and then restore it
+
+# illegal_argument_exception: Provided password hash uses [NOOP] but the configured hashing algorithm is [BCRYPT]
+users/10_basic.yml:
+  - Test put user with password hash
+
+# Slash in index name is not escaped (BUG)
+security/authz/13_index_datemath.yml:
+  - Test indexing documents with datemath, when permitted
+
+# Possibly a cluster health color mismatch...
+security/authz/14_cat_indices.yml:
+
+# Test looks for "testnode.crt", but "ca.crt" is returned first
+ssl/10_basic.yml:
+  - Test get SSL certificates
+
+# class org.elasticsearch.xpack.vectors.query.VectorScriptDocValues$DenseVectorScriptDocValues cannot be cast to class org.elasticsearch.xpack.vectors.query.VectorScriptDocValues$SparseVectorScriptDocValues ...
+vectors/30_sparse_vector_basic.yml:
+  - Dot Product
+# java.lang.IllegalArgumentException: No field found for [my_dense_vector] in mapping
+vectors/40_sparse_vector_special_cases.yml:
+  - Vectors of different dimensions and data types
+  - Dimensions can be sorted differently
+  - Distance functions for documents missing vector field should return 0
+
+# Cannot connect to Docker IP
+watcher/execute_watch/60_http_input.yml:
+
+# Test tries to match on "tagline", which requires "human=false", which doesn't work in the Go API.
+# Also test does too much within a single test, so has to be disabled as whole, unfortunately.
+xpack/15_basic.yml:
+
+# Test uses "y" as a property name, which is parsed as 'true' in the Go YAML library;
+# see https://yaml.org/type/bool.html
+ml/explain_data_frame_analytics.yml:
+  - Test empty data frame given body
+  - Test non-empty data frame given body
+runtime_fields/10_keyword.yml:
+  - docvalue_fields
+  - fetch fields
+
+# Test uses "n" as a property name, which is parsed as 'false' in the Go YAML library;
+search.aggregation/10_histogram.yml:
+
+# Getting "no matching index template found for data stream [invalid-data-stream]"
+data_stream/10_basic.yml:
+  - Create data stream with invalid name
+
+# The matcher like 'indices.0.aliases.0' points to internal index
+data_stream/80_resolve_index_data_streams.yml:
+  - Resolve index with indices, aliases, and data streams
+  - Resolve index with hidden and closed indices
+
+# Zero matchers like '...shards.0.stores.0.allocation:primary' expect array, not map
+data_stream/40_supported_apis.yml:
+  - Verify shard stores api
+
+# Failing with error 'Index [.security] is not on the current version. Security features relying on the index will not be available until the upgrade API is run on the index'
+data_stream/40_supported_apis.yml:
+  - Verify search shards api
+  - Verify shard stores api
+  - Verify rank eval with data streams
+  - Verify get field mappings api
+  - Open write index for data stream opens all backing indices
+data_stream/90_reindex.yml:
+  - Reindex from data stream into an index
+
+# Error: constant 9223372036854775808 overflows int (https://play.golang.org/p/7pUdz-_Pdom)
+unsigned_long/10_basic.yml:
+unsigned_long/20_null_value.yml:
+unsigned_long/30_multi_fields.yml:
+unsigned_long/40_different_numeric.yml:
+unsigned_long/50_script_values.yml:
+unsigned_long/60_collapse.yml:
+
+# Cannot compare float64 ending with .0 reliably due to inconsistent serialisation (https://github.com/golang/go/issues/26363)
+search/330_fetch_fields.yml:
+  - Test nested field inside object structure
+
+search/350_point_in_time.yml:
+  - msearch
+
+nodes.stats/11_indices_metrics.yml:
+  - Metric - http
+  - Metric - blank for indices shards
+  - Metric - _all for indices shards
+  - indices shards total count test
+
+searchable_snapshots/10_usage.yml:
+  - Tests searchable snapshots usage stats with full_copy and shared_cache indices
+
+# Expects count 2 but returns only 1
+service_accounts/10_basic.yml:
+  - Test service account tokens
+`
diff --git a/internal/cmd/generate/commands/gentests/testdata/cluster.health/10_basic.yml b/internal/build/cmd/generate/commands/gentests/testdata/cluster.health/10_basic.yml
old mode 100755
new mode 100644
similarity index 100%
rename from internal/cmd/generate/commands/gentests/testdata/cluster.health/10_basic.yml
rename to internal/build/cmd/generate/commands/gentests/testdata/cluster.health/10_basic.yml
diff --git a/internal/cmd/generate/commands/gentests/testdata/info/10_basic.yml b/internal/build/cmd/generate/commands/gentests/testdata/info/10_basic.yml
old mode 100755
new mode 100644
similarity index 100%
rename from internal/cmd/generate/commands/gentests/testdata/info/10_basic.yml
rename to internal/build/cmd/generate/commands/gentests/testdata/info/10_basic.yml
diff --git a/internal/cmd/generate/commands/gentests/testdata/info/20_lucene_version.yml b/internal/build/cmd/generate/commands/gentests/testdata/info/20_lucene_version.yml
old mode 100755
new mode 100644
similarity index 100%
rename from internal/cmd/generate/commands/gentests/testdata/info/20_lucene_version.yml
rename to internal/build/cmd/generate/commands/gentests/testdata/info/20_lucene_version.yml
diff --git a/internal/build/cmd/tools/commands/spec/command.go b/internal/build/cmd/tools/commands/spec/command.go
new file mode 100644
index 0000000000..fa1549871c
--- /dev/null
+++ b/internal/build/cmd/tools/commands/spec/command.go
@@ -0,0 +1,305 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cmd
+
+import (
+	"archive/zip"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
+	"github.com/elastic/go-elasticsearch/v7/internal/build/utils"
+	"github.com/elastic/go-elasticsearch/v7/internal/version"
+	"github.com/spf13/cobra"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+var (
+	output     *string
+	commitHash *string
+	debug      *bool
+	info       *bool
+)
+
+func init() {
+	output = toolsCmd.Flags().StringP("output", "o", "", "Path to a folder for generated output")
+	commitHash = toolsCmd.Flags().StringP("commit_hash", "c", "", "Elasticsearch commit hash")
+	debug = toolsCmd.Flags().BoolP("debug", "d", false, "Print the generated source to terminal")
+	info = toolsCmd.Flags().Bool("info", false, "Print the API details to terminal")
+
+	cmd.RegisterCmd(toolsCmd)
+}
+
+var toolsCmd = &cobra.Command{
+	Use:   "download-spec",
+	Short: "Downdload specification artifact for code & tests generation",
+	Run: func(cmd *cobra.Command, args []string) {
+		command := &Command{
+			Output:     *output,
+			CommitHash: *commitHash,
+			Debug:      *debug,
+			Info:       *info,
+		}
+		err := command.Execute()
+		if err != nil {
+			utils.PrintErr(err)
+			os.Exit(1)
+		}
+	},
+}
+
+type Command struct {
+	Output     string
+	CommitHash string
+	Debug      bool
+	Info       bool
+}
+
+// download-spec runs a query to the Elastic artifact API, retrieve the list of active artifacts
+// downloads, extract and write to disk the rest-resources spec alongside a json with relevant build information.
+func (c Command) Execute() (err error) {
+	const artifactsUrl = "https://artifacts-api.elastic.co/v1/versions"
+
+	esBuildVersion := os.Getenv("ELASTICSEARCH_BUILD_VERSION")
+	if esBuildVersion == "" {
+		esBuildVersion = version.Client
+	}
+
+	versionUrl := strings.Join([]string{artifactsUrl, esBuildVersion}, "/")
+
+	res, err := http.Get(versionUrl)
+	if err != nil {
+		log.Fatalf(err.Error())
+	}
+	defer res.Body.Close()
+
+	var v Versions
+	dec := json.NewDecoder(res.Body)
+	err = dec.Decode(&v)
+	if err != nil {
+		log.Fatalf(err.Error())
+	}
+
+	if c.Debug {
+		log.Printf("%d builds found", len(v.Version.Builds))
+	}
+
+	var build Build
+	if c.CommitHash != "" {
+		if build, err = findBuildByCommitHash(c.CommitHash, v.Version.Builds); err != nil {
+			build = findMostRecentBuild(v.Version.Builds)
+		}
+	} else {
+		build = findMostRecentBuild(v.Version.Builds)
+	}
+	if c.Debug {
+		log.Printf("Build found : %s", build.Projects.Elasticsearch.CommitHash)
+	}
+
+	data, err := c.downloadZip(build)
+	if err != nil {
+		log.Fatalf("Cannot download zip from %s, reason : %s", build.zipfileUrl(), err)
+	}
+
+	if err := c.extractZipToDest(data); err != nil {
+		log.Fatalf(err.Error())
+	}
+
+	d, _ := json.Marshal(build)
+
+	err = c.writeFileToDest("elasticsearch.json", d)
+	if err != nil {
+		log.Fatalf(err.Error())
+	}
+
+	return nil
+}
+
+func (c Command) writeFileToDest(filename string, data []byte) error {
+	path := filepath.Join(c.Output, filename)
+	if err := ioutil.WriteFile(path, data, 0644); err != nil {
+		return fmt.Errorf("cannot write file: %s", err)
+	}
+	if c.Debug {
+		log.Printf("Successfuly written file to : %s", path)
+	}
+	return nil
+}
+
+type Versions struct {
+	Version struct {
+		Builds []Build `json:"builds"`
+	} `json:"version"`
+}
+
+type PackageUrl struct {
+	*url.URL
+}
+
+func (p *PackageUrl) UnmarshalJSON(data []byte) error {
+	if string(data) == "null" {
+		return nil
+	}
+	url, err := url.Parse(string(data[1 : len(data)-1]))
+	if err == nil {
+		p.URL = url
+	}
+	return err
+}
+
+type BuildStartTime struct {
+	*time.Time
+}
+
+func (t *BuildStartTime) UnmarshalJSON(data []byte) error {
+	if string(data) == "null" {
+		return nil
+	}
+	var err error
+	parsedTime, err := time.Parse(`"`+"Mon, 2 Jan 2006 15:04:05 MST"+`"`, string(data))
+	t.Time = &parsedTime
+	return err
+}
+
+type Build struct {
+	StartTime BuildStartTime `json:"start_time"`
+	Version   string         `json:"version"`
+	BuildId   string         `json:"build_id"`
+	Projects  struct {
+		Elasticsearch struct {
+			Branch     string `json:"branch"`
+			CommitHash string `json:"commit_hash"`
+			Packages   map[string]struct {
+				Url  PackageUrl `json:"url"`
+				Type string     `json:"type"`
+			}
+		} `json:"elasticsearch"`
+	} `json:"projects"`
+}
+
+func NewBuild() Build {
+	t := time.Date(1970, 0,0,0,0,0,0, time.UTC)
+	startTime := BuildStartTime{Time: &t}
+	return Build{StartTime: startTime}
+}
+
+// zipfileUrl return the file URL for the rest-resources artifact from Build
+// There should be only one artifact matching the requirements par Build.
+func (b Build) zipfileUrl() string {
+	for _, pack := range b.Projects.Elasticsearch.Packages {
+		if pack.Type == "zip" && strings.Contains(pack.Url.String(), "rest-resources") {
+			return pack.Url.String()
+		}
+	}
+	return ""
+}
+
+// extractZipToDest extract the data from a previously downloaded file loaded in memory to Output target.
+func (c Command) extractZipToDest(data []byte) error {
+	zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
+	if err != nil {
+		return err
+	}
+
+	if err = os.MkdirAll(c.Output, 0744); err != nil {
+		return fmt.Errorf("cannot created destination directory: %s", err)
+	}
+
+	for _, file := range zipReader.File {
+		f, err := file.Open()
+		if err != nil {
+			return fmt.Errorf("cannot read file in zipfile: %s", err)
+		}
+
+		if file.FileInfo().IsDir() {
+			path := filepath.Join(c.Output, file.Name)
+			_ = os.MkdirAll(path, 0744)
+		} else {
+			data, err := ioutil.ReadAll(f)
+			if err != nil {
+				return err
+			}
+
+			if err := c.writeFileToDest(file.Name, data); err != nil {
+				return err
+			}
+		}
+	}
+
+	if c.Debug {
+		log.Printf("Zipfile successfully extracted to %s", c.Output)
+	}
+
+	return nil
+}
+
+// downloadZip fetches the rest-resources artifact from a Build and return its content as []byte.
+func (c Command) downloadZip(b Build) ([]byte, error) {
+	url := b.zipfileUrl()
+	if c.Debug {
+		log.Printf("Zipfile url : %s", b.zipfileUrl())
+	}
+
+	client := &http.Client{}
+
+	req, err := http.NewRequest(http.MethodGet, url, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Add("Accept-Content", "gzip")
+	res, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+
+	data, _ := ioutil.ReadAll(res.Body)
+	return data, err
+}
+
+// findMostRecentBuild iterates through the builds retrieved from the api
+// and return the latest one based on the StartTime of each Build.
+func findMostRecentBuild(builds []Build) Build {
+	var latestBuild Build
+	latestBuild = NewBuild()
+	for _, build := range builds {
+		if build.StartTime.After(*latestBuild.StartTime.Time) {
+			latestBuild = build
+		}
+	}
+	return latestBuild
+}
+
+// findBuildByCommitHash iterates through the builds and returns the first occurrence of Build
+// that matches the provided commitHash.
+func findBuildByCommitHash(commitHash string, builds []Build) (Build, error) {
+	for _, build := range builds {
+		if build.Projects.Elasticsearch.CommitHash == commitHash {
+			return build, nil
+		}
+	}
+	return Build{}, fmt.Errorf("Build with commit hash %s not found", commitHash)
+}
diff --git a/internal/build/cmd/tools/commands/spec/command_test.go b/internal/build/cmd/tools/commands/spec/command_test.go
new file mode 100644
index 0000000000..79a480be75
--- /dev/null
+++ b/internal/build/cmd/tools/commands/spec/command_test.go
@@ -0,0 +1,66 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cmd
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+func TestBuild_zipfileUrl(t *testing.T) {
+	tests := []struct {
+		name   string
+		json   string
+		want   string
+	}{
+		{
+			name: "Simple test with valid url",
+			json: `
+			{
+			  "start_time": "Mon, 19 Apr 2021 12:15:47 GMT",
+			  "version": "8.0.0-SNAPSHOT",
+			  "build_id": "8.0.0-ab7cd914",
+			  "projects": {
+				"elasticsearch": {
+				  "branch": "master",
+				  "commit_hash": "d3be79018b5b70a118ea5a897a539428b728df5a",
+				  "Packages": {
+					"rest-resources-zip-8.0.0-SNAPSHOT.zip": {
+					  "url": "https://snapshots.elastic.co/8.0.0-ab7cd914/downloads/elasticsearch/rest-resources-zip-8.0.0-SNAPSHOT.zip",
+					  "type": "zip"
+					}
+				  }
+				}
+			  }
+			}
+			`,
+			want: "https://snapshots.elastic.co/8.0.0-ab7cd914/downloads/elasticsearch/rest-resources-zip-8.0.0-SNAPSHOT.zip",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			b := Build{}
+			if err := json.Unmarshal([]byte(tt.json), &b); err != nil {
+				t.Fatalf(err.Error())
+			}
+			if got := b.zipfileUrl(); got != tt.want {
+				t.Errorf("zipfileUrl() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
\ No newline at end of file
diff --git a/internal/build/go.mod b/internal/build/go.mod
new file mode 100644
index 0000000000..4386c83564
--- /dev/null
+++ b/internal/build/go.mod
@@ -0,0 +1,16 @@
+module github.com/elastic/go-elasticsearch/v7/internal/build
+
+go 1.15
+
+replace github.com/elastic/go-elasticsearch/v7 => ../../
+
+require (
+	github.com/alecthomas/chroma v0.8.2
+	github.com/elastic/go-elasticsearch/v7 v7
+	github.com/spf13/cobra v1.1.3
+	github.com/stretchr/testify v1.4.0 // indirect
+	golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
+	golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
+	golang.org/x/tools v0.1.0
+	gopkg.in/yaml.v2 v2.4.0
+)
diff --git a/internal/build/go.sum b/internal/build/go.sum
new file mode 100644
index 0000000000..745fec8248
--- /dev/null
+++ b/internal/build/go.sum
@@ -0,0 +1,341 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
+github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg=
+github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
+github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/internal/build/main.go b/internal/build/main.go
new file mode 100644
index 0000000000..c14b0f302f
--- /dev/null
+++ b/internal/build/main.go
@@ -0,0 +1,32 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+	"github.com/elastic/go-elasticsearch/v7/internal/build/cmd"
+
+	_ "github.com/elastic/go-elasticsearch/v7/internal/build/cmd/generate/commands/genexamples"
+	_ "github.com/elastic/go-elasticsearch/v7/internal/build/cmd/generate/commands/gensource"
+	_ "github.com/elastic/go-elasticsearch/v7/internal/build/cmd/generate/commands/genstruct"
+	_ "github.com/elastic/go-elasticsearch/v7/internal/build/cmd/generate/commands/gentests"
+	_ "github.com/elastic/go-elasticsearch/v7/internal/build/cmd/tools/commands/spec"
+)
+
+func main() {
+	cmd.Execute()
+}
diff --git a/internal/build/utils/chromatize.go b/internal/build/utils/chromatize.go
new file mode 100644
index 0000000000..389fcc3625
--- /dev/null
+++ b/internal/build/utils/chromatize.go
@@ -0,0 +1,54 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+import (
+	"bytes"
+	"io"
+	"io/ioutil"
+
+	"github.com/alecthomas/chroma/formatters"
+	"github.com/alecthomas/chroma/lexers"
+	"github.com/alecthomas/chroma/styles"
+)
+
+// Chromatize returns a syntax highlighted Go code.
+//
+func Chromatize(r io.Reader) (io.Reader, error) {
+	var b bytes.Buffer
+	lexer := lexers.Get("go")
+
+	contents, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	it, err := lexer.Tokenise(nil, string(contents))
+	if err != nil {
+		return nil, err
+	}
+
+	style, _ := styles.Get("pygments").Builder().Build()
+	formatter := formatters.Get("terminal256")
+	err = formatter.Format(&b, style, it)
+	if err != nil {
+		return nil, err
+	}
+
+	return &b, nil
+}
diff --git a/internal/cmd/generate/utils/debug.go b/internal/build/utils/debug.go
old mode 100755
new mode 100644
similarity index 68%
rename from internal/cmd/generate/utils/debug.go
rename to internal/build/utils/debug.go
index 5b2e44a228..1c2ec1d9ac
--- a/internal/cmd/generate/utils/debug.go
+++ b/internal/build/utils/debug.go
@@ -1,3 +1,20 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package utils
 
 import (
diff --git a/internal/build/utils/map.go b/internal/build/utils/map.go
new file mode 100644
index 0000000000..8b1745c8a6
--- /dev/null
+++ b/internal/build/utils/map.go
@@ -0,0 +1,42 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+// MapKeys returns the map keys as a slice of strings.
+//
+func MapKeys(s interface{}) (keys []string) {
+	if s, ok := s.(map[interface{}]interface{}); ok {
+		for k := range s {
+			if k, ok := k.(string); ok {
+				keys = append(keys, k)
+			}
+		}
+	}
+	return keys
+}
+
+// MapValues returns the map values as a slice of interfaces.
+//
+func MapValues(s interface{}) (values []interface{}) {
+	if s, ok := s.(map[interface{}]interface{}); ok {
+		for _, v := range s {
+			values = append(values, v)
+		}
+	}
+	return values
+}
diff --git a/internal/build/utils/metadata.go b/internal/build/utils/metadata.go
new file mode 100644
index 0000000000..7cd6f83cfb
--- /dev/null
+++ b/internal/build/utils/metadata.go
@@ -0,0 +1,93 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+var resVersion = regexp.MustCompile(`(\d+\.(x|\d+.\d+)).*`)
+
+// EsVersion returns the Elasticsearch from environment variable, Java property file, or an error.
+//
+func EsVersion(fpath string) (string, error) {
+	if envEsVersion := os.Getenv("ELASTICSEARCH_BUILD_VERSION"); envEsVersion != "" {
+		splitVersion := resVersion.FindStringSubmatch(envEsVersion)
+		return splitVersion[1], nil
+	} else {
+		return "", fmt.Errorf("ELASTICSEARCH_BUILD_VERSION is empty")
+	}
+}
+
+// GitCommit returns the Git commit from environment variable or parsing information from fpath, or an error.
+//
+func GitCommit(fpath string) (string, error) {
+	if esBuildHash := os.Getenv("ELASTICSEARCH_BUILD_HASH"); esBuildHash != "" {
+		return esBuildHash[:7], nil
+	}
+	return "", fmt.Errorf("ELASTICSEARCH_BUILD_HASH is empty")
+}
+
+// GitTag returns the Git tag for fpath if available, or an error.
+//
+func GitTag(fpath string) (string, error) {
+	basePath, err := basePathFromFilepath(fpath)
+	if err != nil {
+		return "", fmt.Errorf("GitCommit: %s", err)
+	}
+
+	commit, err := GitCommit(fpath)
+	if err != nil {
+		return "", fmt.Errorf("GitTag: %s", err)
+	}
+
+	args := strings.Split("git --git-dir="+basePath+".git tag --points-at "+commit, " ")
+	cmd := exec.Command(args[0:1][0], args[1:]...)
+	// fmt.Printf("> %s\n", strings.Join(cmd.Args, " "))
+
+	out, err := cmd.Output()
+	if err != nil {
+		return "", nil
+	}
+
+	return strings.TrimSpace(string(out)), nil
+}
+
+func basePathFromFilepath(fpath string) (string, error) {
+	var bpath strings.Builder
+
+	fpath, err := filepath.Abs(fpath)
+	if err != nil {
+		return "", err
+	}
+
+	for _, p := range strings.Split(fpath, string(filepath.Separator)) {
+		if p == "rest-api-spec" {
+			break
+		}
+		bpath.WriteString(p)
+		bpath.WriteRune(filepath.Separator)
+	}
+
+	return bpath.String(), nil
+}
diff --git a/internal/build/utils/naming.go b/internal/build/utils/naming.go
new file mode 100644
index 0000000000..ae64fee17e
--- /dev/null
+++ b/internal/build/utils/naming.go
@@ -0,0 +1,142 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+import "strings"
+
+var (
+	// Options: boolean, enum, list, number, string, time
+	typesToGo = map[string]string{
+		"boolean": "*bool",
+		"enum":    "string", // TODO: Custom "enum" type
+		"list":    "[]string",
+		"number":  "*int",
+		"int":     "*int",
+		"long":    "*int",
+		"string":  "string",
+		"time":    "time.Duration",
+	}
+)
+
+// APIToGo returns the Go version of API call, eg. cluster.health => ClusterHealth
+//
+func APIToGo(s string) string {
+	ep := strings.Split(s, ".")
+	ns := make([]string, len(ep))
+	for _, v := range ep {
+		m := strings.Split(v, "_")
+		mn := make([]string, len(m))
+		for _, vv := range m {
+			mn = append(mn, NameToGo(vv))
+		}
+		ns = append(ns, strings.Join(mn, ""))
+	}
+	return strings.Join(ns, "")
+}
+
+// NameToGo returns a Go version of name, eg. node_id => NodeID.
+//
+func NameToGo(s string, api ...string) string {
+	exceptions := map[string]string{
+		"index": "Index",
+		"id":    "DocumentID",
+		"type":  "DocumentType",
+	}
+
+	acronyms := map[string]string{
+		"ip":  "IP",
+		"id":  "ID",
+		"ttl": "TTL",
+
+		"api":   "API",
+		"ccr":   "CCR",
+		"ilm":   "ILM",
+		"ml":    "ML",
+		"sql":   "SQL",
+		"ssl":   "SSL",
+		"xpack": "XPack",
+	}
+
+	specialMappingsForID := map[string]string{
+		"DeleteScript":         "ScriptID",
+		"GetScript":            "ScriptID",
+		"PutScript":            "ScriptID",
+		"IngestDeletePipeline": "PipelineID",
+		"IngestGetPipeline":    "PipelineID",
+		"IngestPutPipeline":    "PipelineID",
+		"IngestSimulate":       "PipelineID",
+		"RenderSearchTemplate": "TemplateID",
+
+		"MLDeleteDataFrameAnalytics":   "ID",
+		"MLGetDataFrameAnalytics":      "ID",
+		"MLGetDataFrameAnalyticsStats": "ID",
+		"MLPutDataFrameAnalytics":      "ID",
+		"MLStartDataFrameAnalytics":    "ID",
+		"MLStopDataFrameAnalytics":     "ID",
+
+		"RollupDeleteJob":     "JobID",
+		"RollupGetJobs":       "JobID",
+		"RollupGetRollupCaps": "Index",
+		"RollupPutJob":        "JobID",
+		"RollupStartJob":      "JobID",
+		"RollupStopJob":       "JobID",
+
+		"SecurityGetAPIKey": "ID",
+
+		"WatcherDeleteWatch":  "WatchID",
+		"WatcherExecuteWatch": "WatchID",
+		"WatcherGetWatch":     "WatchID",
+		"WatcherPutWatch":     "WatchID",
+	}
+
+	if s == "id" && api != nil && len(api) > 0 && api[0] != "" && specialMappingsForID[api[0]] != "" {
+		return specialMappingsForID[api[0]]
+	}
+
+	if value, ok := exceptions[s]; ok {
+		return value
+	}
+
+	ep := strings.Split(s, "_")
+	ns := make([]string, len(ep))
+	for _, v := range ep {
+		if value, ok := acronyms[v]; ok {
+			v = value
+		} else if v == "uuid" {
+			v = "UUID"
+		}
+		ns = append(ns, strings.Title(v))
+	}
+	return strings.Join(ns, "")
+}
+
+// TypeToGo returns a Go version of type, eg. boolean => *bool.
+//
+func TypeToGo(s string, comment ...bool) string {
+	// If the string contains a pipe character, it's a polymorphic parameter,
+	// ie. it takes heterogeous values, such as "boolean" and "number"
+	if strings.Contains(s, "|") {
+		return "interface{}"
+	}
+
+	if v, ok := typesToGo[s]; ok {
+		return v
+	}
+
+	return "interface{}"
+}
diff --git a/internal/build/utils/strings.go b/internal/build/utils/strings.go
new file mode 100644
index 0000000000..7b9792ebe0
--- /dev/null
+++ b/internal/build/utils/strings.go
@@ -0,0 +1,32 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+import (
+	"regexp"
+)
+
+var (
+	reIDString = regexp.MustCompile(`\bid\b`)
+)
+
+// IDToUpper returns a string with all occurrences of "id" capitalized.
+//
+func IDToUpper(s string) string {
+	return reIDString.ReplaceAllLiteralString(s, "ID")
+}
diff --git a/internal/build/utils/terminal.go b/internal/build/utils/terminal.go
new file mode 100644
index 0000000000..641bed76c6
--- /dev/null
+++ b/internal/build/utils/terminal.go
@@ -0,0 +1,64 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package utils
+
+import (
+	"fmt"
+	"os"
+
+	"golang.org/x/crypto/ssh/terminal"
+)
+
+var (
+	isTTY  bool
+	tWidth int
+)
+
+func init() {
+	isTTY = terminal.IsTerminal(int(os.Stderr.Fd()))
+	tWidth, _, _ = terminal.GetSize(int(os.Stdout.Fd()))
+}
+
+// PrintErr prints an error to STDERR.
+//
+func PrintErr(err error) {
+	if isTTY {
+		fmt.Fprint(os.Stderr, "\x1b[1;37;41m")
+	}
+	fmt.Fprintf(os.Stderr, "ERROR: %s", err)
+	if isTTY {
+		fmt.Fprint(os.Stderr, "\x1b[0m")
+	}
+	fmt.Fprint(os.Stderr, "\n")
+}
+
+// IsTTY returns true when os.Stderr is a terminal.
+//
+func IsTTY() bool {
+	return isTTY
+}
+
+// TerminalWidth returns the width of terminal, or zero.
+//
+func TerminalWidth() int {
+	if tWidth < 0 {
+		return 0
+	}
+
+	return tWidth
+}
diff --git a/internal/cmd/generate/commands/commands.go b/internal/cmd/generate/commands/commands.go
deleted file mode 100755
index ffc3c62bb8..0000000000
--- a/internal/cmd/generate/commands/commands.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package commands
-
-import (
-	"os"
-
-	"github.com/spf13/cobra"
-
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
-)
-
-var rootCmd = &cobra.Command{
-	Use:   "generate",
-	Short: "generate allows you to generate APIs and tests",
-	// Long:  "TODO",
-}
-
-// Execute launches the CLI application.
-//
-func Execute() {
-	if err := rootCmd.Execute(); err != nil {
-		utils.PrintErr(err)
-		os.Exit(1)
-	}
-}
-
-// RegisterCmd adds a command to rootCmd.
-//
-func RegisterCmd(cmd *cobra.Command) {
-	rootCmd.AddCommand(cmd)
-}
diff --git a/internal/cmd/generate/commands/gensource/debug.go b/internal/cmd/generate/commands/gensource/debug.go
deleted file mode 100755
index b1e57f6038..0000000000
--- a/internal/cmd/generate/commands/gensource/debug.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package gensource
-
-import (
-	"fmt"
-	"strings"
-	"text/tabwriter"
-
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/utils"
-)
-
-// DebugInfo returns information about the endpoint as a string.
-//
-func (e *Endpoint) DebugInfo() string {
-	var out strings.Builder
-	w := tabwriter.NewWriter(&out, 0, 0, 1, ' ', 0)
-
-	fmt.Fprintln(&out, strings.Repeat("─", utils.TerminalWidth()))
-	fmt.Fprintf(&out, "API: %s (%s)\n", e.MethodWithNamespace(), e.Name)
-	// fmt.Fprintf(&out, "<%s>\n", e.Documentation)
-	fmt.Fprintln(&out, strings.Repeat("─", utils.TerminalWidth()))
-
-	fmt.Fprintf(&out, "Methods:\n  %s\n", e.Methods)
-
-	fmt.Fprintln(&out, "Paths:")
-	for _, path := range e.URL.Paths {
-		fmt.Fprintf(&out, "  • %s\n", path)
-	}
-
-	if len(e.URL.Parts) > 0 {
-		fmt.Fprintln(&out, "Parts:")
-		for _, part := range e.URL.Parts {
-			fmt.Fprintf(w, "  • %s\t", part.Name)
-			fmt.Fprintf(w, "  %s", part.Type)
-			if part.Required {
-				fmt.Fprint(w, ", required")
-			}
-			fmt.Fprint(w, "\n")
-		}
-		w.Flush()
-	}
-
-	if len(e.URL.Params) > 0 {
-		fmt.Fprintln(&out, "Params:")
-		for _, param := range e.URL.Params {
-			fmt.Fprintf(w, "  • %s\t %s", param.Name, param.Type)
-			if param.Required {
-				fmt.Fprint(w, ", required")
-			}
-			if param.Type == "enum" {
-				fmt.Fprintf(w, ": %s", strings.Join(param.Options, ", "))
-			}
-			fmt.Fprint(w, "\n")
-		}
-		w.Flush()
-	}
-
-	if e.Body != nil {
-		fmt.Fprint(&out, "Body: ")
-		if e.Body.Required {
-			fmt.Fprintf(&out, "required")
-		} else {
-			fmt.Fprintf(&out, "optional")
-		}
-		if e.Body.ContentType != "" {
-			fmt.Fprintf(&out, " (format: %s)", e.Body.ContentType)
-		}
-		fmt.Fprintf(&out, "\n")
-	}
-
-	return out.String()
-}
diff --git a/internal/cmd/generate/commands/gensource/generator_test.go b/internal/cmd/generate/commands/gensource/generator_test.go
deleted file mode 100755
index b1abba7f4b..0000000000
--- a/internal/cmd/generate/commands/gensource/generator_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package gensource_test
-
-import (
-	"io/ioutil"
-	"os"
-	"strings"
-	"testing"
-
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/commands/gensource"
-)
-
-func TestGenerator(t *testing.T) {
-	t.Run("Output", func(t *testing.T) {
-		f, err := os.Open("testdata/info.json")
-		if err != nil {
-			t.Fatalf("Error: %s", err)
-		}
-
-		endpoint, err := gensource.NewEndpoint(f)
-		if err != nil {
-			t.Fatalf("Error creating endpoint for %q: %s", f.Name(), err)
-		}
-
-		gen := gensource.Generator{Endpoint: endpoint}
-
-		out, err := gen.OutputFormatted()
-		if err != nil {
-			t.Fatalf("Error generating output for %q: %s", f.Name(), err)
-		}
-
-		s, err := ioutil.ReadAll(out)
-		if err != nil {
-			t.Fatalf("Error reading output for %q: %s", f.Name(), err)
-		}
-		// t.Logf("\n%s\n", s)
-
-		if !strings.Contains(string(s), "func newInfoFunc(t Transport) Info {") {
-			t.Errorf("Incorrect output")
-		}
-	})
-}
diff --git a/internal/cmd/generate/commands/gensource/testdata/info.json b/internal/cmd/generate/commands/gensource/testdata/info.json
deleted file mode 100755
index 63754eb7f7..0000000000
--- a/internal/cmd/generate/commands/gensource/testdata/info.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "info": {
-    "documentation": "http://www.elastic.co/guide/",
-    "methods": ["GET"],
-    "url": {
-      "path": "/",
-      "paths": ["/"],
-      "parts": {
-      },
-      "params": {
-      }
-    },
-    "body": null
-  }
-}
diff --git a/internal/cmd/generate/commands/gentests/generator.go b/internal/cmd/generate/commands/gentests/generator.go
deleted file mode 100755
index 20d3cec655..0000000000
--- a/internal/cmd/generate/commands/gentests/generator.go
+++ /dev/null
@@ -1,783 +0,0 @@
-package gentests
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"strconv"
-	"strings"
-
-	"golang.org/x/tools/imports"
-)
-
-var (
-	goruncache map[string]string
-)
-
-func init() {
-	goruncache = make(map[string]string)
-}
-
-// Generator represents the "gentests" generator.
-//
-type Generator struct {
-	b bytes.Buffer
-
-	TestSuite TestSuite
-}
-
-// Output returns the generator output.
-//
-func (g *Generator) Output() (io.Reader, error) {
-	g.genFileHeader()
-	g.w("func Test" + g.TestSuite.Name() + "(t *testing.T) {\n")
-	g.genInitializeClient()
-	g.genHelpers()
-	g.genCommonSetup()
-	if len(g.TestSuite.Setup) > 0 {
-		g.w("// ----- Test Suite Setup --------------------------------------------------------\n")
-		g.w("testSuiteSetup := func() {\n")
-		g.genSetupTeardown(g.TestSuite.Setup)
-		g.w("}\n")
-		g.w("// --------------------------------------------------------------------------------\n")
-		g.w("\n")
-	}
-	if len(g.TestSuite.Teardown) > 0 {
-		g.w("\t// Teardown\n")
-		g.w("\tdefer func() {\n")
-		g.genSetupTeardown(g.TestSuite.Teardown)
-		g.w("\t}()\n")
-	}
-	for i, t := range g.TestSuite.Tests {
-		g.w("\n")
-		g.genLocationYAML(t)
-		g.w("\t" + `t.Run("` + strings.Title(t.Name) + `", ` + "func(t *testing.T) {\n")
-		g.genSkip(t)
-		g.w("\tdefer recoverPanic(t)\n")
-		g.w("\tcommonSetup()\n")
-		if len(g.TestSuite.Setup) > 0 {
-			g.w("\ttestSuiteSetup()\n")
-		}
-		g.w("\n")
-		if len(t.Setup) > 0 {
-			g.w("\t// Test setup\n")
-			g.genSetupTeardown(t.Setup)
-		}
-		if len(t.Teardown) > 0 {
-			g.w("\t// Test teardown\n")
-			g.w("\tdefer func() {\n")
-			g.genSetupTeardown(t.Teardown)
-			g.w("\t}()\n")
-		}
-		if len(t.Setup) > 0 || len(t.Teardown) > 0 {
-			g.w("\n")
-		}
-		g.genSteps(t)
-		g.w("\t})\n")
-		if i < len(g.TestSuite.Tests)-1 {
-			g.w("\n")
-		}
-	}
-	g.w("}\n")
-	return bytes.NewReader(g.b.Bytes()), nil
-}
-
-// OutputFormatted returns a formatted generator output.
-//
-func (g *Generator) OutputFormatted() (io.Reader, error) {
-	out, err := g.Output()
-	if err != nil {
-		return bytes.NewReader(g.b.Bytes()), err
-	}
-
-	var b bytes.Buffer
-	if _, err := io.Copy(&b, out); err != nil {
-		return bytes.NewReader(g.b.Bytes()), err
-	}
-
-	fout, err := imports.Process(
-		"",
-		g.b.Bytes(),
-		&imports.Options{
-			AllErrors:  true,
-			Comments:   true,
-			FormatOnly: false,
-			TabIndent:  true,
-			TabWidth:   1,
-		})
-	if err != nil {
-		return bytes.NewReader(b.Bytes()), err
-	}
-
-	g.b.Reset()
-	g.b.Write(fout)
-
-	return bytes.NewReader(fout), nil
-}
-
-func (g *Generator) w(s string) {
-	g.b.WriteString(s)
-}
-
-func (g *Generator) gorun(code string) (string, error) {
-	if goruncache[code] != "" {
-		return goruncache[code], nil
-	}
-
-	dir, err := ioutil.TempDir("tmp", "gorun")
-	if err != nil {
-		return "", fmt.Errorf("gorun: %s", err)
-	}
-	f, err := os.Create(filepath.Join(dir, "type_for_struct_field.go"))
-	if err != nil {
-		return "", fmt.Errorf("gorun: %s", err)
-	}
-	defer func() {
-		f.Close()
-		os.RemoveAll(dir)
-	}()
-
-	// fmt.Println(code)
-	if err := ioutil.WriteFile(f.Name(), []byte(code), 0644); err != nil {
-		return "", fmt.Errorf("gorun: %s", err)
-	}
-
-	cmd := exec.Command("go", "run", f.Name())
-	out, err := cmd.Output()
-	if err != nil {
-		if e, ok := err.(*exec.ExitError); ok {
-			return "", fmt.Errorf("gorun: %s", e.Stderr)
-		}
-		return "", fmt.Errorf("gorun: %s", err)
-	}
-
-	goruncache[code] = string(out)
-
-	return string(out), nil
-}
-
-func (g *Generator) genFileHeader() {
-	g.w("// Code generated")
-	if EsVersion != "" || GitCommit != "" || GitTag != "" {
-		g.w(" from YAML test suite version")
-		if GitCommit != "" {
-			g.w(fmt.Sprintf(" %s", GitCommit))
-			if GitTag != "" {
-				g.w(fmt.Sprintf("|%s", GitTag))
-			}
-		}
-	}
-	g.w(" -- DO NOT EDIT\n")
-	g.w("\n")
-	g.w("package esapi_test\n")
-	g.w(`
-import (
-	encjson "encoding/json"
-	encyaml "gopkg.in/yaml.v2"
-	"testing"
-
-	"github.com/elastic/go-elasticsearch"
-	"github.com/elastic/go-elasticsearch/esapi"
-)
-
-var (
-	// Prevent compilation errors for unused packages
-	_ = encjson.NewDecoder
-	_ = encyaml.NewDecoder
-	_ = fmt.Printf
-)` + "\n")
-}
-
-func (g *Generator) genInitializeClient() {
-	g.w(`	es, eserr := elasticsearch.NewDefaultClient()
-	if eserr != nil {
-		t.Fatalf("Error creating the client: %s\n", eserr)
-	}
-
-`)
-}
-
-func (g *Generator) genHelpers() {
-	g.w(`recoverPanic := func(t *testing.T) {
-	reLocation := regexp.MustCompile("(.*_test.go:\\d+).*")
-	if rec := recover(); rec != nil {
-		var loc string
-		s := strings.Split(string(debug.Stack()), "\n")
-		for i := len(s) - 1; i >= 0; i-- {
-			if reLocation.MatchString(s[i]) {
-				loc = strings.TrimSpace(s[i])
-				break
-			}
-		}
-		t.Fatalf("Panic: %s in %s", rec, reLocation.ReplaceAllString(loc, "$1"))
-	}
-}
-` + "\n")
-
-	g.w(`debug := func(v interface{}) {
-		if os.Getenv("DEBUG") != "" {
-			t.Logf("%s", v)
-		}
-	}
-`)
-	g.w(`
-	handleResponseError := func(t *testing.T, res *esapi.Response) {
-		if res.IsError() {
-			t.Logf("Response error: %s", res)
-			// t.Fatalf("Response error: %s", res.Status())
-		}
-	}
-	_ = handleResponseError
-`)
-	g.w("\n\n")
-}
-
-func (g *Generator) genCommonSetup() {
-	// TODO: Full setup
-	// https://github.com/elastic/elasticsearch-ruby/blob/master/elasticsearch-api/test/integration/yaml_test_runner.rb
-	g.w(`
-	// ----- Common Setup -------------------------------------------------------------
-	commonSetup := func() {
-		var res *esapi.Response
-		res, _ = es.Indices.Delete([]string{"_all"})
-		res.Body.Close()
-
-		res, _ = es.Indices.DeleteTemplate("*")
-		res.Body.Close()
-
-		res, _ = es.Indices.DeleteAlias([]string{"_all"}, []string{"_all"})
-		res.Body.Close()
-
-		res, _ = es.Snapshot.Delete("test_repo_create_1", "test_snapshot")
-		res.Body.Close()
-		res, _ = es.Snapshot.Delete("test_repo_restore_1", "test_snapshot")
-		res.Body.Close()
-		res, _ = es.Snapshot.Delete("test_cat_snapshots_1", "snap1")
-		res.Body.Close()
-		res, _ = es.Snapshot.Delete("test_cat_snapshots_1", "snap2")
-		res.Body.Close()
-		for _, n := range []string{"test_repo_create_1", "test_repo_restore_1", "test_repo_get_1", "test_repo_get_2", "test_repo_status_1", "test_cat_repo_1", "test_cat_repo_2", "test_cat_snapshots_1"} {
-			res, _ = es.Snapshot.DeleteRepository([]string{n})
-			res.Body.Close()
-		}
-	}
-	commonSetup()
-	// --------------------------------------------------------------------------------
-
-	`)
-}
-
-func (g *Generator) genLocationYAML(t Test) {
-	f, err := os.Open(t.Filepath)
-	if err != nil {
-		g.w(fmt.Sprintf("// Error opening file: %s\n", err))
-	}
-
-	scanner := bufio.NewScanner(f)
-	var i int
-	for scanner.Scan() {
-		i++
-		tname := scanner.Text()
-		tname = strings.TrimRight(tname, `:`)
-		tname = strings.NewReplacer(`\"`, `"`).Replace(tname)
-		tname = strings.TrimPrefix(tname, `"`)
-		tname = strings.TrimSuffix(tname, `"`)
-
-		if tname == t.OrigName {
-			// TODO: Github URL (with proper branch/commit/etc)
-			g.w("\t// Source: " + t.Filepath + fmt.Sprintf(":%d", i) + "\n\t//\n")
-		}
-	}
-	if err := scanner.Err(); err != nil {
-		g.w(fmt.Sprintf("// Error reading file: %s\n", err))
-	}
-}
-
-func (g *Generator) genSkip(t Test) {
-	// Check the custom skip list
-	if skips, ok := skipTests[t.BaseFilename()]; ok {
-		if len(skips) < 1 {
-			g.w("\t// Skipping all tests in '" + t.BaseFilename() + "'\n")
-			g.w("\tt.SkipNow()\n\n")
-			return
-		}
-
-		for _, skip := range skips {
-			if skip == t.OrigName {
-				g.w("\tt.SkipNow()\n\n")
-			}
-		}
-	}
-
-	// Check the skip property coming from YAML
-	if t.Skip {
-		if t.SkipInfo != "" {
-			g.w("\tt.Skip(" + strconv.Quote(t.SkipInfo) + ")\n\n")
-		} else {
-			g.w("\tt.SkipNow()\n\n")
-		}
-	}
-}
-
-func (g *Generator) genSetupTeardown(actions []Action) {
-	g.genVarSection(Test{})
-
-	for _, a := range actions {
-		g.genAction(a, false)
-		g.w("\n")
-	}
-}
-
-func (g *Generator) genSteps(t Test) {
-	var skipBody bool
-	if !t.Steps.ContainsAssertion() && !t.Steps.ContainsCatch() && !t.Steps.ContainsStash() {
-		skipBody = true
-	}
-	g.genVarSection(t, skipBody)
-
-	for _, step := range t.Steps {
-		switch step.(type) {
-		case Action:
-			// Generate debug info
-			var dbg strings.Builder
-			dbg.WriteString("\t\t// => " + step.(Action).Method() + "(")
-			var j int
-			for k, v := range step.(Action).Params() {
-				j++
-				dbg.WriteString(k + ": " + strings.Replace(fmt.Sprintf("%v", v), "\n", "|", -1))
-				if j < len(step.(Action).Params()) {
-					dbg.WriteString(", ")
-				}
-			}
-			dbg.WriteString(") ")
-			pad := 101 - dbg.Len()
-			if pad < 0 {
-				pad = 0
-			}
-			g.w(dbg.String() + strings.Repeat("-", pad) + "\n\t\t//\n")
-
-			// Generate the action
-			g.genAction(step.(Action), skipBody)
-			g.w("\t\t// " + strings.Repeat("-", 96) + "\n\n")
-		case Assertion:
-			// Generate debug info
-			g.w("\t\t// ~> ")
-			g.w(fmt.Sprintf("%q: ", step.(Assertion).operation))
-			g.w(strings.Replace(fmt.Sprintf("%s", step.(Assertion).payload), "\n", "|", -1))
-			g.w("\n")
-			// Generate the assertion
-			g.genAssertion(step.(Assertion))
-			g.w("\n")
-		case Stash:
-			// Generate setting the stash
-			g.genStashSet(step.(Stash))
-			g.w("\n")
-		default:
-			panic(fmt.Sprintf("Unknown step %T", step))
-		}
-	}
-}
-
-func (g *Generator) genVarSection(t Test, skipBody ...bool) {
-	g.w("\t\tvar (\n")
-	g.w("\t\t\treq esapi.Request\n")
-	g.w("\t\t\tres *esapi.Response\n")
-	g.w("\t\t\terr error\n\n")
-
-	g.w("\t\t\tstash = make(map[string]interface{}, 0)\n\n")
-
-	if (len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false)) &&
-		(t.Steps.ContainsAssertion() || t.Steps.ContainsCatch() || true) {
-		g.w("\t\t\tbody []byte\n")
-		g.w("\t\t\tmapi map[string]interface{}\n")
-		g.w("\t\t\tslic []interface{}\n")
-	}
-
-	if t.Steps.ContainsAssertion("is_false", "is_true") {
-		g.w("\n\t\t\tvalue reflect.Value\n")
-	}
-
-	g.w("\n")
-	g.w("\t\t\tassertion bool\n")
-
-	g.w("\t\t\tactual   interface{}\n")
-	g.w("\t\t\texpected interface{}\n")
-	g.w("\n")
-
-	if t.Steps.ContainsAssertion("match", "match-regexp") {
-		g.w("\n\t\t\tre *regexp.Regexp\n")
-		g.w("\t\t\tmatch bool\n")
-	}
-
-	g.w("\t\t)\n\n")
-
-	if (len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false)) &&
-		(t.Steps.ContainsAssertion() || t.Steps.ContainsCatch() || true) {
-		g.w("\t\t_ = mapi\n")
-		g.w("\t\t_ = slic\n")
-		g.w("\n")
-		g.w(`handleResponseBody := func(res *esapi.Response) {
-			// Reset deserialized structures
-			mapi = make(map[string]interface{})
-			slic = make([]interface{}, 0)
-
-			var err error
-			body, err = ioutil.ReadAll(res.Body)
-			if err != nil {
-				t.Fatalf("Error reading body: %s", err)
-			}
-			res.Body.Close()
-			res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
-
-			if len(body) < 1 {
-				// FIXME: Hack to prevent EOF errors
-				return
-			}
-
-			if len(res.Header) > 0 {
-				if strings.Contains(res.Header["Content-Type"][0], "text/plain") {
-					return
-				}
-
-				if strings.Contains(res.Header["Content-Type"][0], "yaml") {
-					if strings.HasPrefix(string(body), "---\n-") {
-						if err := encyaml.NewDecoder(res.Body).Decode(&slic); err != nil {
-							t.Fatalf("Error parsing the response body: %s", err)
-						}
-					} else {
-						if err := encyaml.NewDecoder(res.Body).Decode(&mapi); err != nil {
-							t.Fatalf("Error parsing the response body: %s", err)
-						}
-					}
-					return
-				}
-			}
-
-			d := encjson.NewDecoder(res.Body)
-			d.UseNumber()
-
-			if strings.HasPrefix(string(body), "[") {
-				if err := d.Decode(&slic); err != nil {
-					t.Fatalf("Error parsing the response body: %s", err)
-				}
-			} else {
-				if err := d.Decode(&mapi); err != nil {
-					t.Fatalf("Error parsing the response body: %s", err)
-				}
-			}
-		}` + "\n")
-	}
-
-	g.w("\n")
-
-	g.w("\t\t_ = stash\n")
-
-	if t.Steps.ContainsAssertion("is_false", "is_true") {
-		g.w("\t\t_ = value\n")
-	}
-
-	g.w("\t\t_ = assertion\n")
-
-	g.w("\t\t_ = actual\n")
-	g.w("\t\t_ = expected\n")
-
-	if t.Steps.ContainsAssertion("match", "match-regexp") {
-		g.w("\n")
-		g.w("\t\t_ = re\n")
-		g.w("\t\t_ = match\n")
-	}
-
-	g.w("\n")
-}
-
-func (g *Generator) genAction(a Action, skipBody ...bool) {
-	// Initialize the request
-	g.w("\t\treq = esapi." + a.Request() + "{\n")
-
-	// Pass the parameters
-	for k, v := range a.Params() {
-		// fmt.Printf("%s.%s: <%T> %v\n", a.Request(), k, v, v)
-
-		if strings.HasPrefix(fmt.Sprintf("%s", v), "$") {
-			v = `stash[` + strconv.Quote(fmt.Sprintf("%s", v)) + `]`
-		}
-
-		switch v.(type) {
-		case bool:
-			g.w("\t\t\t" + k + ": ")
-
-			typ, ok := apiRegistry[a.Request()][k]
-			if !ok {
-				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
-			}
-
-			switch typ {
-			case "bool":
-				g.w(strconv.FormatBool(v.(bool)))
-			case "*bool":
-				g.w(`esapi.BoolPtr(` + strconv.FormatBool(v.(bool)) + `)`)
-			case "string":
-				g.w(`"` + strconv.FormatBool(v.(bool)) + `"`)
-			case "[]string":
-				// TODO: Listify
-				g.w(`[]string{"` + strconv.FormatBool(v.(bool)) + `"}`)
-			default:
-				g.w(strconv.FormatBool(v.(bool)))
-			}
-			g.w(",\n")
-
-		case string:
-			if k == "Body" {
-				g.w("\t\t\t" + k + ": ")
-				body := v.(string)
-				if !strings.HasSuffix(body, "\n") {
-					body = body + "\n"
-				}
-				g.w("strings.NewReader(`" + body + "`)")
-			} else {
-				g.w("\t\t\t" + k + ": ")
-				// TODO: Handle comma separated strings as lists
-
-				typ, ok := apiRegistry[a.Request()][k]
-				if !ok {
-					panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
-				}
-
-				var value string
-				if strings.HasPrefix(v.(string), "stash[") {
-					switch typ {
-					case "bool":
-						value = `fmt.Sprintf("%v", ` + v.(string) + `)`
-					case "string":
-						value = fmt.Sprintf("%s.(string)", v)
-					case "[]string":
-						// TODO: Comma-separated list => Quoted list
-						value = fmt.Sprintf(`[]string{%s.(string)}`, v)
-					case "int":
-						value = `func() int {
-				switch ` + v.(string) + `.(type) {
-				case int:
-					return ` + v.(string) + `.(int)
-				case float64:
-					return int(` + v.(string) + `.(float64))
-				}
-				case json.Number:
-					v, _ := ` + v.(string) + `.(encjson.Number).Int64()
-					vv := int(v)
-					return vv
-				panic(fmt.Sprintf(` + "`" + `Unexpected type %T for ` + v.(string) + "`" + `, ` + v.(string) + `))
-			}()`
-					case "*int":
-						value = `func() *int {
-				switch ` + v.(string) + `.(type) {
-				case int:
-					v := ` + v.(string) + `.(int)
-					return &v
-				case float64:
-					v := int(` + v.(string) + `.(float64))
-					return &v
-				case json.Number:
-					v, _ := ` + v.(string) + `.(encjson.Number).Int64()
-					vv := int(v)
-					return &vv
-				}
-				panic(fmt.Sprintf(` + "`" + `Unexpected type %T for ` + v.(string) + "`" + `, ` + v.(string) + `))
-			}()`
-					case "time.Duration":
-						value = `fmt.Sprintf("%d", ` + v.(string) + `)`
-					default:
-						panic(fmt.Sprintf("Unexpected type %q for value %v", typ, v))
-					}
-				} else {
-					switch typ {
-					case "[]string":
-						value = `[]string{` + fmt.Sprintf("%q", v) + `}`
-					case "time.Duration":
-						re := regexp.MustCompile("^(\\d+).*")
-						value = re.ReplaceAllString(fmt.Sprintf("%s", v), "$1")
-					default:
-						value = fmt.Sprintf("%q", v)
-					}
-				}
-				g.w(value)
-			}
-			g.w(",\n")
-
-		case int, *int, float64:
-			g.w("\t\t\t" + k + ": ")
-
-			typ, ok := apiRegistry[a.Request()][k]
-			if !ok {
-				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
-			}
-
-			var value string
-			switch typ {
-			case "string":
-				value = `"` + fmt.Sprintf("%d", v) + `"`
-			case "[]string":
-				value = `[]string{"` + fmt.Sprintf("%d", v) + `"}`
-			case "time.Duration":
-				re := regexp.MustCompile("^(\\d+).*")
-				value = re.ReplaceAllString(fmt.Sprintf("%d", v), "$1")
-			case "*int":
-				g.w(`esapi.IntPtr(` + fmt.Sprintf("%d", v) + `)`)
-			default:
-				value = fmt.Sprintf("%d", v)
-			}
-			g.w(value)
-			g.w(",\n")
-
-		case []interface{}:
-			g.w("\t\t\t" + k + ": ")
-
-			typ, ok := apiRegistry[a.Request()][k]
-			if !ok {
-				panic(fmt.Sprintf("%s.%s: field not found", a.Request(), k))
-			}
-
-			switch typ {
-			case "string":
-				switch v.(type) {
-				case string:
-					g.w("`" + v.(string) + "`")
-				case []interface{}:
-					vvv := make([]string, 0)
-					for _, vv := range v.([]interface{}) {
-						vvv = append(vvv, fmt.Sprintf("%s", vv))
-					}
-					g.w("`" + strings.Join(vvv, ",") + "`")
-				default:
-					panic(fmt.Sprintf("<%s> %s{}.%s: unexpected value <%T> %#v", typ, a.Request(), k, v, v))
-				}
-			case "[]string":
-				qv := make([]string, 0)
-				for _, vv := range v.([]interface{}) {
-					// TODO: Check type
-					qv = append(qv, fmt.Sprintf("%q", vv.(string)))
-				}
-				g.w(`[]string{` + strings.Join(qv, ",") + `}`)
-			case "io.Reader":
-				// Serialize Bulk payloads ...
-				if k == "Body" {
-					var b strings.Builder
-					for _, vv := range v.([]interface{}) {
-						switch vv.(type) {
-						case string:
-							b.WriteString(vv.(string))
-						default:
-							j, err := json.Marshal(convert(vv))
-							if err != nil {
-								panic(fmt.Sprintf("%s{}.%s: %s (%s)", a.Request(), k, err, v))
-							}
-							b.WriteString(string(j))
-						}
-						b.WriteString("\n")
-					}
-					b.WriteString("\n")
-					g.w("\t\tstrings.NewReader(`" + b.String() + "`)")
-					// ... or just convert the value to JSON
-				} else {
-					j, err := json.Marshal(convert(v))
-					if err != nil {
-						panic(fmt.Sprintf("%s{}.%s: %s (%s)", a.Request(), k, err, v))
-					}
-					g.w("\t\tstrings.NewReader(`" + fmt.Sprintf("%s", j) + "`)")
-				}
-			}
-			g.w(",\n")
-
-		case map[interface{}]interface{}:
-			g.w("\t\t\t" + k + ": ")
-			// vv := unstash(convert(v).(map[string]interface{}))
-			// fmt.Println(vv)
-			j, err := json.Marshal(convert(v))
-			if err != nil {
-				panic(fmt.Sprintf("JSON parse error: %s; %s", err, v))
-			} else {
-				// Unstash values
-				reStash := regexp.MustCompile(`("\$[^"]+")`)
-				j = reStash.ReplaceAll(j, []byte("` + strconv.Quote(fmt.Sprintf(\"%v\", stash[$1])) + `"))
-
-				g.w("\t\tstrings.NewReader(`" + fmt.Sprintf("%s", j) + "`)")
-				g.w(",\n")
-			}
-
-		default:
-			g.w(fmt.Sprintf("\t\t// TODO: %s (%v)\n", k, v))
-		}
-	}
-
-	if len(a.headers) > 0 && strings.Contains(a.headers["Accept"], "yaml") && strings.HasPrefix(a.Request(), "Cat") {
-		g.w("\t\t" + `Format: "yaml",` + "\n")
-	}
-
-	g.w("\t\t}\n\n")
-
-	// Get response
-	g.w("\t\tres, err = req.Do(context.Background(), es)\n")
-
-	g.w(`		if err != nil {
-			t.Fatalf("ERROR: %s", err)
-		}
-		defer res.Body.Close()
-		debug(res)
-	`)
-
-	g.w("\n\n")
-
-	if len(a.catch) < 1 {
-		// Handle error responses
-		g.w(`		handleResponseError(t, res)` + "\n")
-	} else {
-		// TODO: Test catch
-	}
-
-	if len(skipBody) < 1 || (len(skipBody) > 0 && skipBody[0] == false) {
-		// Read and parse the body
-		g.w(`		handleResponseBody(res)` + "\n")
-	}
-}
-
-func (g *Generator) genAssertion(a Assertion) {
-	g.w(a.Condition())
-	g.w(a.Error() + "\n")
-	g.w("}\n") // Close the condition
-}
-
-func (g *Generator) genStashSet(s Stash) {
-	g.w(fmt.Sprintf("// Set %q\n", s.Key()))
-	g.w(fmt.Sprintf("stash[%q] = %s\n", s.Key(), s.Value()))
-}
-
-func convert(i interface{}) interface{} {
-	switch x := i.(type) {
-	case map[interface{}]interface{}:
-		m2 := map[string]interface{}{}
-		for k, v := range x {
-			var ks string
-			switch k.(type) {
-			case string:
-				ks = k.(string)
-			case int:
-				ks = fmt.Sprintf("%d", k)
-			default:
-				ks = fmt.Sprintf("%v", k)
-			}
-			m2[ks] = convert(v)
-		}
-		return m2
-	case []interface{}:
-		for i, v := range x {
-			x[i] = convert(v)
-		}
-	}
-	return i
-}
diff --git a/internal/cmd/generate/commands/gentests/skips.go b/internal/cmd/generate/commands/gentests/skips.go
deleted file mode 100755
index 98d9562e9e..0000000000
--- a/internal/cmd/generate/commands/gentests/skips.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package gentests
-
-import (
-	"fmt"
-	"strings"
-
-	"gopkg.in/yaml.v2"
-)
-
-var skipTests map[string][]string
-
-func init() {
-	err := yaml.NewDecoder(strings.NewReader(skipTestsYAML)).Decode(&skipTests)
-	if err != nil {
-		panic(fmt.Sprintf("ERROR: %v", err))
-	}
-}
-
-var skipFiles = []string{
-	"update/85_fields_meta.yml",            // Uses non-existing API property
-	"update/86_fields_meta_with_types.yml", // --||--
-}
-
-// TODO: Comments into descriptions for `Skip()`
-//
-var skipTestsYAML = `
----
-# Cannot distinguish between missing value for refresh and an empty string
-bulk/50_refresh.yml:
-  - refresh=empty string immediately makes changes are visible in search
-bulk/51_refresh_with_types.yml:
-  - refresh=empty string immediately makes changes are visible in search
-create/60_refresh.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-create/61_refresh_with_types.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-delete/50_refresh.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-delete/51_refresh_with_types.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-index/60_refresh.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-index/61_refresh_with_types.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-update/60_refresh.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-update/61_refresh_with_types.yml:
-  - When refresh url parameter is an empty string that means "refresh immediately"
-
-# Stash in value
-cluster.reroute/11_explain.yml:
-nodes.info/30_settings.yml:
-nodes.stats/20_response_filtering.yml:
-nodes.stats/30_discovery.yml:
-  - Discovery stats
-nodes.discovery/30_discovery.yml:
-  - Discovery stats
-
-# Parsed response is YAML: value is map[interface {}]interface {}, not map[string]interface {}
-cat.aliases/20_headers.yml:
-  - Simple alias with yaml body through Accept header
-
-# Incorrect int instead of float in match (aggregations.date_range.buckets.0.from: 1000000); TODO: PR
-search.aggregation/40_range.yml:
-  - Date range
-
-# No support for headers per request yet
-tasks.list/10_basic.yml:
-  - tasks_list headers
-
-# Not relevant
-search/issue4895.yml:
-search/issue9606.yml:
-
-# FIXME
-bulk/80_cas.yml:
-bulk/81_cas_with_types.yml:
-
-`
diff --git a/internal/cmd/generate/go.mod b/internal/cmd/generate/go.mod
deleted file mode 100644
index 6d139cc800..0000000000
--- a/internal/cmd/generate/go.mod
+++ /dev/null
@@ -1,16 +0,0 @@
-module github.com/elastic/go-elasticsearch/internal/cmd/generate
-
-go 1.11
-
-replace github.com/elastic/go-elasticsearch => ../../../
-
-require (
-	github.com/alecthomas/chroma v0.6.3
-	github.com/elastic/go-elasticsearch v0.0.0-00010101000000-000000000000 // indirect
-	github.com/inconshreveable/mousetrap v1.0.0 // indirect
-	github.com/spf13/cobra v0.0.3
-	github.com/spf13/pflag v1.0.3 // indirect
-	golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c
-	golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c
-	gopkg.in/yaml.v2 v2.2.2
-)
diff --git a/internal/cmd/generate/go.sum b/internal/cmd/generate/go.sum
deleted file mode 100644
index fc43c0b526..0000000000
--- a/internal/cmd/generate/go.sum
+++ /dev/null
@@ -1,44 +0,0 @@
-github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
-github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
-github.com/alecthomas/chroma v0.6.3 h1:8H1D0yddf0mvgvO4JDBKnzLd9ERmzzAijBxnZXGV/FA=
-github.com/alecthomas/chroma v0.6.3/go.mod h1:quT2EpvJNqkuPi6DmBHB+E33FXBgBBPzyH5++Dn1LPc=
-github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
-github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
-github.com/alecthomas/kong v0.1.15/go.mod h1:0m2VYms8rH0qbCqVB2gvGHk74bqLIq0HXjCs5bNbNQU=
-github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
-github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
-github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
-github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
-github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c h1:hbqcUGBwEHdDbhy8EluQIkbwTIbOvaYedVBif4f2mFQ=
-golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/cmd/generate/main.go b/internal/cmd/generate/main.go
deleted file mode 100755
index 498b6f9166..0000000000
--- a/internal/cmd/generate/main.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package main
-
-import (
-	"github.com/elastic/go-elasticsearch/internal/cmd/generate/commands"
-	_ "github.com/elastic/go-elasticsearch/internal/cmd/generate/commands/gensource"
-	_ "github.com/elastic/go-elasticsearch/internal/cmd/generate/commands/gentests"
-)
-
-func main() {
-	commands.Execute()
-}
diff --git a/internal/cmd/generate/utils/chromatize.go b/internal/cmd/generate/utils/chromatize.go
deleted file mode 100755
index b8e35fd8d0..0000000000
--- a/internal/cmd/generate/utils/chromatize.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package utils
-
-import (
-	"bytes"
-	"io"
-	"io/ioutil"
-
-	"github.com/alecthomas/chroma/formatters"
-	"github.com/alecthomas/chroma/lexers"
-	"github.com/alecthomas/chroma/styles"
-)
-
-// Chromatize returns a syntax highlighted Go code.
-//
-func Chromatize(r io.Reader) (io.Reader, error) {
-	var b bytes.Buffer
-	lexer := lexers.Get("go")
-
-	contents, err := ioutil.ReadAll(r)
-	if err != nil {
-		return nil, err
-	}
-
-	it, err := lexer.Tokenise(nil, string(contents))
-	if err != nil {
-		return nil, err
-	}
-
-	style, _ := styles.Get("pygments").Builder().Build()
-	formatter := formatters.Get("terminal256")
-	err = formatter.Format(&b, style, it)
-	if err != nil {
-		return nil, err
-	}
-
-	return &b, nil
-}
diff --git a/internal/cmd/generate/utils/map.go b/internal/cmd/generate/utils/map.go
deleted file mode 100755
index 1292785b82..0000000000
--- a/internal/cmd/generate/utils/map.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package utils
-
-// MapKeys returns the map keys as a slice of strings.
-//
-func MapKeys(s interface{}) (keys []string) {
-	if s, ok := s.(map[interface{}]interface{}); ok {
-		for k := range s {
-			if k, ok := k.(string); ok {
-				keys = append(keys, k)
-			}
-		}
-	}
-	return keys
-}
-
-// MapValues returns the map values as a slice of interfaces.
-//
-func MapValues(s interface{}) (values []interface{}) {
-	if s, ok := s.(map[interface{}]interface{}); ok {
-		for _, v := range s {
-			values = append(values, v)
-		}
-	}
-	return values
-}
diff --git a/internal/cmd/generate/utils/metadata.go b/internal/cmd/generate/utils/metadata.go
deleted file mode 100755
index cb1520cc3e..0000000000
--- a/internal/cmd/generate/utils/metadata.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package utils
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"strings"
-)
-
-var (
-	reEsVersion = regexp.MustCompile(`elasticsearch\s+=\s+(\d+\.\d+\.\d+)`)
-)
-
-// EsVersion returns the Elasticsearch from Java property file, or an error.
-//
-func EsVersion(fpath string) (string, error) {
-	basePath, err := basePathFromFilepath(fpath)
-	if err != nil {
-		return "", fmt.Errorf("EsVersion: %s", err)
-	}
-
-	c, err := ioutil.ReadFile(filepath.Join(basePath, "buildSrc", "version.properties"))
-	if err != nil {
-		return "", fmt.Errorf("EsVersion: %s", err)
-	}
-
-	m := reEsVersion.FindSubmatch(c)
-	if len(m) < 2 {
-		return "", nil
-	}
-	return string(m[1]), nil
-}
-
-// GitCommit returns the Git commit for fpath, or an error.
-//
-func GitCommit(fpath string) (string, error) {
-	if gitCommitEnv := os.Getenv("ELASTICSEARCH_BUILD_HASH"); gitCommitEnv != "" {
-		return gitCommitEnv, nil
-	}
-
-	basePath, err := basePathFromFilepath(fpath)
-	if err != nil {
-		return "", fmt.Errorf("GitCommit: %s", err)
-	}
-
-	args := strings.Split("git --git-dir="+basePath+".git rev-parse --short HEAD", " ")
-	cmd := exec.Command(args[0:1][0], args[1:]...)
-	// fmt.Printf("> %s\n", strings.Join(cmd.Args, " "))
-
-	out, err := cmd.Output()
-	if err != nil {
-		return "", fmt.Errorf("GitCommit: %s", err)
-	}
-	return strings.TrimSpace(string(out)), nil
-}
-
-// GitTag returns the Git tag for fpath if available, or an error.
-//
-func GitTag(fpath string) (string, error) {
-	basePath, err := basePathFromFilepath(fpath)
-	if err != nil {
-		return "", fmt.Errorf("GitCommit: %s", err)
-	}
-
-	commit, err := GitCommit(fpath)
-	if err != nil {
-		return "", fmt.Errorf("GitTag: %s", err)
-	}
-
-	args := strings.Split("git --git-dir="+basePath+".git tag --points-at "+commit, " ")
-	cmd := exec.Command(args[0:1][0], args[1:]...)
-	// fmt.Printf("> %s\n", strings.Join(cmd.Args, " "))
-
-	out, err := cmd.Output()
-	if err != nil {
-		return "", nil
-	}
-
-	return strings.TrimSpace(string(out)), nil
-}
-
-func basePathFromFilepath(fpath string) (string, error) {
-	var bpath strings.Builder
-
-	fpath, err := filepath.Abs(fpath)
-	if err != nil {
-		return "", err
-	}
-
-	for _, p := range strings.Split(fpath, string(filepath.Separator)) {
-		if p == "rest-api-spec" {
-			break
-		}
-		bpath.WriteString(p)
-		bpath.WriteRune(filepath.Separator)
-	}
-
-	return bpath.String(), nil
-}
diff --git a/internal/cmd/generate/utils/naming.go b/internal/cmd/generate/utils/naming.go
deleted file mode 100755
index 29fb68712a..0000000000
--- a/internal/cmd/generate/utils/naming.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package utils
-
-import "strings"
-
-var (
-	// Options: boolean, enum, list, number, string, time
-	typesToGo = map[string]string{
-		"boolean": "*bool",
-		"enum":    "string", // TODO: Custom "enum" type
-		"list":    "[]string",
-		"number":  "*int",
-		"string":  "string",
-		"time":    "time.Duration",
-	}
-)
-
-// NameToGo returns a Go version of name, eg. node_id => NodeID.
-//
-func NameToGo(s string) string {
-	exceptions := map[string]string{"index": "Index", "id": "DocumentID", "type": "DocumentType"}
-	if value, ok := exceptions[s]; ok {
-		return value
-	}
-
-	ep := strings.Split(s, "_")
-	ns := make([]string, len(ep))
-	for _, v := range ep {
-		if v == "id" {
-			v = "ID"
-		}
-		ns = append(ns, strings.Title(v))
-	}
-	return strings.Join(ns, "")
-}
-
-// TypeToGo returns a Go version of type, eg. boolean => *bool.
-//
-func TypeToGo(s string, comment ...bool) string {
-	// If the string contains a pipe character, it's a polymorphic parameter,
-	// ie. it takes heterogeous values, such as "boolean" and "number"
-	if strings.Contains(s, "|") {
-		return "interface{}"
-	}
-
-	if v, ok := typesToGo[s]; ok {
-		return v
-	}
-
-	return "interface{}"
-}
diff --git a/internal/cmd/generate/utils/strings.go b/internal/cmd/generate/utils/strings.go
deleted file mode 100755
index 5265d41726..0000000000
--- a/internal/cmd/generate/utils/strings.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package utils
-
-import (
-	"regexp"
-)
-
-var (
-	reIDString = regexp.MustCompile(`\bid\b`)
-)
-
-// IDToUpper returns a string with all occurrences of "id" capitalized.
-//
-func IDToUpper(s string) string {
-	return reIDString.ReplaceAllLiteralString(s, "ID")
-}
diff --git a/internal/cmd/generate/utils/terminal.go b/internal/cmd/generate/utils/terminal.go
deleted file mode 100755
index 73cafb5caf..0000000000
--- a/internal/cmd/generate/utils/terminal.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package utils
-
-import (
-	"fmt"
-	"os"
-
-	"golang.org/x/crypto/ssh/terminal"
-)
-
-var (
-	isTTY  bool
-	tWidth int
-)
-
-func init() {
-	isTTY = terminal.IsTerminal(int(os.Stderr.Fd()))
-	tWidth, _, _ = terminal.GetSize(int(os.Stdout.Fd()))
-}
-
-// PrintErr prints an error to STDERR.
-//
-func PrintErr(err error) {
-	if isTTY {
-		fmt.Fprint(os.Stderr, "\x1b[1;37;41m")
-	}
-	fmt.Fprintf(os.Stderr, "ERROR: %s", err)
-	if isTTY {
-		fmt.Fprint(os.Stderr, "\x1b[0m")
-	}
-	fmt.Fprint(os.Stderr, "\n")
-}
-
-// IsTTY returns true when os.Stderr is a terminal.
-//
-func IsTTY() bool {
-	return isTTY
-}
-
-// TerminalWidth returns the width of terminal, or zero.
-//
-func TerminalWidth() int {
-	if tWidth < 0 {
-		return 0
-	}
-
-	return tWidth
-}
diff --git a/internal/version/version.go b/internal/version/version.go
index dd00c32edf..51297dde90 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -1,5 +1,22 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
 package version
 
 // Client returns the client version as a string.
 //
-const Client = "7.0.0-SNAPSHOT"
+const Client = "7.16.3-SNAPSHOT"