> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://api.qdrant.tech/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://api.qdrant.tech/_mcp/server.

# Batch update points

POST http://localhost:6333/collections/{collection_name}/points/batch
Content-Type: application/json

Batch updates points, including their respective vectors and payloads.

Reference: https://api.qdrant.tech/api-reference/points/batch-update

## Authentication

- `api-key` header (required) — API Key authentication via header

## Servers

- `http://localhost:6333` (http, default)
- `https://localhost:6333` (https)

## Request

### Path parameters

- `collection_name` (string, required) — Name of the collection to apply operations on

### Query parameters

- `wait` (boolean, optional) — If true, wait for changes to actually happen
- `ordering` (enum, optional) — define ordering guarantees for the operation
  - Allowed values: `weak`, `medium`, `strong`
- `timeout` (integer, optional) — Timeout for the operation

### Body (application/json)

This endpoint expects an UpdateOperations.

- `operations` (list of UpdateOperation, required)

## Response

### 200

successful operation

- `usage` (CollectionsCollectionNamePointsBatchPostResponsesContentApplicationJsonSchemaUsage, optional)
- `time` (double, optional) — Time spent to process this request
- `status` (string, optional)
- `result` (list of UpdateResult, optional)

## Types

### UpdateOperation

### CollectionsCollectionNamePointsBatchPostResponsesContentApplicationJsonSchemaUsage

### UpdateResult

- `status` (enum, required) — `Acknowledged` - Request is saved to WAL and will be process in a queue. `Completed` - Request is completed, changes are actual. `WaitTimeout` - Request is waiting for timeout.
  - Allowed values: `acknowledged`, `completed`, `wait_timeout`
- `operation_id` (uint64, optional, nullable) — Sequential number of the operation

### UpsertOperation

- `upsert` (PointInsertOperations, required)

### DeleteOperation

- `delete` (PointsSelector, required)

### SetPayloadOperation

- `set_payload` (SetPayload, required) — This data structure is used in API interface and applied across multiple shards

### OverwritePayloadOperation

- `overwrite_payload` (SetPayload, required) — This data structure is used in API interface and applied across multiple shards

### DeletePayloadOperation

- `delete_payload` (DeletePayload, required) — This data structure is used in API interface and applied across multiple shards

### ClearPayloadOperation

- `clear_payload` (PointsSelector, required)

### UpdateVectorsOperation

- `update_vectors` (UpdateVectors, required)

### DeleteVectorsOperation

- `delete_vectors` (DeleteVectors, required)

### Usage

Usage of the hardware resources, spent to process the request

- `hardware` (UsageHardware, optional)
- `inference` (UsageInference, optional)

### PointInsertOperations

### PointsSelector

### SetPayload

This data structure is used in API interface and applied across multiple shards

- `payload` (map from string to any, required)
- `points` (list of ExtendedPointId, optional, nullable) — Assigns payload to each point in this list
- `filter` (SetPayloadFilter, optional) — Assigns payload to each point that satisfy this filter condition
- `shard_key` (SetPayloadShardKey, optional)
- `key` (string, optional, nullable) — Assigns payload to each point that satisfy this path of property

### DeletePayload

This data structure is used in API interface and applied across multiple shards

- `keys` (list of string, required) — List of payload keys to remove from payload
- `points` (list of ExtendedPointId, optional, nullable) — Deletes values from each point in this list
- `filter` (DeletePayloadFilter, optional) — Deletes values from points that satisfy this filter condition
- `shard_key` (DeletePayloadShardKey, optional)

### UpdateVectors

- `points` (list of PointVectors, required) — Points with named vectors
- `shard_key` (UpdateVectorsShardKey, optional)
- `update_filter` (UpdateVectorsUpdateFilter, optional)

### DeleteVectors

- `vector` (list of string, required) — Vector names
- `points` (list of ExtendedPointId, optional, nullable) — Deletes values from each point in this list
- `filter` (DeleteVectorsFilter, optional) — Deletes values from points that satisfy this filter condition
- `shard_key` (DeleteVectorsShardKey, optional)

### UsageHardware

### UsageInference

### PointsBatch

- `batch` (Batch, required)
- `shard_key` (PointsBatchShardKey, optional)
- `update_filter` (PointsBatchUpdateFilter, optional) — Filter to apply when updating existing points. Only points matching this filter will be updated. Points that don't match will keep their current state. New points will be inserted regardless of the filter.
- `update_mode` (PointsBatchUpdateMode, optional) — Mode of the upsert operation: insert_only, upsert (default), update_only

### PointsList

- `points` (list of PointStruct, required)
- `shard_key` (PointsListShardKey, optional)
- `update_filter` (PointsListUpdateFilter, optional) — Filter to apply when updating existing points. Only points matching this filter will be updated. Points that don't match will keep their current state. New points will be inserted regardless of the filter.
- `update_mode` (PointsListUpdateMode, optional) — Mode of the upsert operation: insert_only, upsert (default), update_only

### PointIdsList

- `points` (list of ExtendedPointId, required)
- `shard_key` (PointIdsListShardKey, optional)

### FilterSelector

- `filter` (Filter, required)
- `shard_key` (FilterSelectorShardKey, optional)

### ExtendedPointId

Type, used for specifying point ID in user interface

### SetPayloadFilter

Assigns payload to each point that satisfy this filter condition

### SetPayloadShardKey

### DeletePayloadFilter

Deletes values from points that satisfy this filter condition

### DeletePayloadShardKey

### PointVectors

- `id` (ExtendedPointId, required) — Type, used for specifying point ID in user interface
- `vector` (VectorStruct, required) — Full vector data per point separator with single and multiple vector modes

### UpdateVectorsShardKey

### UpdateVectorsUpdateFilter

### DeleteVectorsFilter

Deletes values from points that satisfy this filter condition

### DeleteVectorsShardKey

### HardwareUsage

Usage of the hardware resources, spent to process the request

- `cpu` (integer, required)
- `payload_io_read` (integer, required)
- `payload_io_write` (integer, required)
- `payload_index_io_read` (integer, required)
- `payload_index_io_write` (integer, required)
- `vector_io_read` (integer, required)
- `vector_io_write` (integer, required)

### InferenceUsage

- `models` (map from string to ModelUsage, required)

### Batch

- `ids` (list of ExtendedPointId, required)
- `vectors` (BatchVectorStruct, required)
- `payloads` (list of BatchPayloadsItems, optional, nullable)

### PointsBatchShardKey

### PointsBatchUpdateFilter

Filter to apply when updating existing points. Only points matching this filter will be updated. Points that don't match will keep their current state. New points will be inserted regardless of the filter.

### PointsBatchUpdateMode

Mode of the upsert operation: insert_only, upsert (default), update_only

### PointStruct

- `id` (ExtendedPointId, required) — Type, used for specifying point ID in user interface
- `vector` (VectorStruct, required) — Full vector data per point separator with single and multiple vector modes
- `payload` (PointStructPayload, optional) — Payload values (optional)

### PointsListShardKey

### PointsListUpdateFilter

Filter to apply when updating existing points. Only points matching this filter will be updated. Points that don't match will keep their current state. New points will be inserted regardless of the filter.

### PointsListUpdateMode

Mode of the upsert operation: insert_only, upsert (default), update_only

### PointIdsListShardKey

### Filter

- `should` (FilterShould, optional) — At least one of those conditions should match
- `min_should` (FilterMinShould, optional) — At least minimum amount of given conditions should match
- `must` (FilterMust, optional) — All conditions must match
- `must_not` (FilterMustNot, optional) — All conditions must NOT match

### FilterSelectorShardKey

### VectorStruct

Full vector data per point separator with single and multiple vector modes

### ModelUsage

- `tokens` (uint64, required)

### BatchVectorStruct

### BatchPayloadsItems

### PointStructPayload

Payload values (optional)

### FilterShould

At least one of those conditions should match

### FilterMinShould

At least minimum amount of given conditions should match

### FilterMust

All conditions must match

### FilterMustNot

All conditions must NOT match

### Document

WARN: Work-in-progress, unimplemented Text document for embedding. Requires inference infrastructure, unimplemented.

- `text` (string, required) — Text of the document. This field will be used as input for the embedding model.
- `model` (string, required) — Name of the model used to generate the vector. List of available models depends on a provider.
- `options` (DocumentOptions, optional) — Additional options for the model, will be passed to the inference service as-is. See model cards for available options.

### Image

WARN: Work-in-progress, unimplemented Image object for embedding. Requires inference infrastructure, unimplemented.

- `image` (any, required) — Image data: base64 encoded image or an URL
- `model` (string, required) — Name of the model used to generate the vector. List of available models depends on a provider.
- `options` (map from string to any, optional, nullable) — Parameters for the model Values of the parameters are model-specific

### InferenceObject

WARN: Work-in-progress, unimplemented Custom object for embedding. Requires inference infrastructure, unimplemented.

- `object` (any, required) — Arbitrary data, used as input for the embedding model. Used if the model requires more than one input or a custom input.
- `model` (string, required) — Name of the model used to generate the vector. List of available models depends on a provider.
- `options` (map from string to any, optional, nullable) — Parameters for the model Values of the parameters are model-specific

### MinShould

- `conditions` (list of Condition, required)
- `min_count` (integer, required)

### DocumentOptions

Option variants for text documents. Ether general-purpose options or BM25-specific options. BM25-specific will only take effect if the `qdrant/bm25` is specified as a model.

### Condition

### Bm25Config

Configuration of the local bm25 models.

- `k` (double, optional, default: 1.2) — Controls term frequency saturation. Higher values mean term frequency has more impact. Default is 1.2
- `b` (double, optional, default: 0.75) — Controls document length normalization. Ranges from 0 (no normalization) to 1 (full normalization). Higher values mean longer documents have less impact. Default is 0.75.
- `avg_len` (double, optional, default: 256) — Expected average document length in the collection. Default is 256.
- `tokenizer` (enum, optional)
  - Allowed values: `prefix`, `whitespace`, `word`, `multilingual`
- `language` (string, optional, nullable) — Defines which language to use for text preprocessing. This parameter is used to construct default stopwords filter and stemmer. To disable language-specific processing, set this to `"language": "none"`. If not specified, English is assumed.
- `lowercase` (boolean, optional, nullable) — Lowercase the text before tokenization. Default is `true`.
- `ascii_folding` (boolean, optional, nullable) — If true, normalize tokens by folding accented characters to ASCII (e.g., "ação" -> "acao"). Default is `false`.
- `stopwords` (Bm25ConfigStopwords, optional) — Configuration of the stopwords filter. Supports list of pre-defined languages and custom stopwords. Default: initialized for specified `language` or English if not specified.
- `stemmer` (Bm25ConfigStemmer, optional) — Configuration of the stemmer. Processes tokens to their root form. Default: initialized Snowball stemmer for specified `language` or English if not specified.
- `min_token_len` (integer, optional, nullable) — Minimum token length to keep. If token is shorter than this, it will be discarded. Default is `None`, which means no minimum length.
- `max_token_len` (integer, optional, nullable) — Maximum token length to keep. If token is longer than this, it will be discarded. Default is `None`, which means no maximum length.

### FieldCondition

All possible payload filtering conditions

- `key` (string, required) — Payload key
- `match` (FieldConditionMatch, optional) — Check if point has field with a given value
- `range` (FieldConditionRange, optional) — Check if points value lies in a given range
- `geo_bounding_box` (FieldConditionGeoBoundingBox, optional) — Check if points geolocation lies in a given area
- `geo_radius` (FieldConditionGeoRadius, optional) — Check if geo point is within a given radius
- `geo_polygon` (FieldConditionGeoPolygon, optional) — Check if geo point is within a given polygon
- `values_count` (FieldConditionValuesCount, optional) — Check number of values of the field
- `is_empty` (boolean, optional, nullable) — Check that the field is empty, alternative syntax for `is_empty: "field_name"`
- `is_null` (boolean, optional, nullable) — Check that the field is null, alternative syntax for `is_null: "field_name"`

### IsEmptyCondition

Select points with empty payload for a specified field

- `is_empty` (PayloadField, required) — Payload field

### IsNullCondition

Select points with null payload for a specified field

- `is_null` (PayloadField, required) — Payload field

### HasIdCondition

ID-based filtering condition

- `has_id` (list of ExtendedPointId, required)

### HasVectorCondition

Filter points which have specific vector assigned

- `has_vector` (string, required)

### NestedCondition

- `nested` (Nested, required) — Select points with payload for a specified nested field

### Bm25ConfigStopwords

Configuration of the stopwords filter. Supports list of pre-defined languages and custom stopwords. Default: initialized for specified `language` or English if not specified.

### Bm25ConfigStemmer

Configuration of the stemmer. Processes tokens to their root form. Default: initialized Snowball stemmer for specified `language` or English if not specified.

### FieldConditionMatch

Check if point has field with a given value

### FieldConditionRange

Check if points value lies in a given range

### FieldConditionGeoBoundingBox

Check if points geolocation lies in a given area

### FieldConditionGeoRadius

Check if geo point is within a given radius

### FieldConditionGeoPolygon

Check if geo point is within a given polygon

### FieldConditionValuesCount

Check number of values of the field

### PayloadField

Payload field

- `key` (string, required) — Payload field name

### Nested

Select points with payload for a specified nested field

- `key` (string, required)
- `filter` (Filter, required)

### GeoBoundingBox

Geo filter request Matches coordinates inside the rectangle, described by coordinates of lop-left and bottom-right edges

- `top_left` (GeoPoint, required) — Geo point payload schema
- `bottom_right` (GeoPoint, required) — Geo point payload schema

### GeoRadius

Geo filter request Matches coordinates inside the circle of `radius` and center with coordinates `center`

- `center` (GeoPoint, required) — Geo point payload schema
- `radius` (double, required) — Radius of the area in meters

### GeoPolygon

Geo filter request Matches coordinates inside the polygon, defined by `exterior` and `interiors`

- `exterior` (GeoLineString, required) — Ordered sequence of GeoPoints representing the line
- `interiors` (list of GeoLineString, optional, nullable) — Interior lines (if present) bound holes within the surface each GeoLineString must consist of a minimum of 4 points, and the first and last points must be the same.

### ValuesCount

Values count filter request

- `lt` (integer, optional, nullable) — point.key.length() \< values\_count.lt
- `gt` (integer, optional, nullable) — point.key.length() > values_count.gt
- `gte` (integer, optional, nullable) — point.key.length() >= values_count.gte
- `lte` (integer, optional, nullable) — point.key.length() \<= values\_count.lte

### GeoPoint

Geo point payload schema

- `lon` (double, required)
- `lat` (double, required)

### GeoLineString

Ordered sequence of GeoPoints representing the line

- `points` (list of GeoPoint, required)

## Examples

**Request**

```json
{
  "operations": [
    {
      "delete": {
        "filter": {}
      }
    }
  ]
}
```

**Response**

```json
{
  "usage": {
    "hardware": {
      "cpu": 1,
      "payload_io_read": 1,
      "payload_io_write": 1,
      "payload_index_io_read": 1,
      "payload_index_io_write": 1,
      "vector_io_read": 1,
      "vector_io_write": 1
    },
    "inference": {
      "models": {}
    }
  },
  "time": 0.002,
  "status": "ok",
  "result": [
    {
      "status": "acknowledged",
      "operation_id": 1
    }
  ]
}
```

**SDK Code**

```python
from qdrant_client import QdrantClient, models

client = QdrantClient(url="http://localhost:6333")

client.batch_update_points(
    collection_name="{collection_name}",
    update_operations=[
        models.UpsertOperation(
            upsert=models.PointsList(
                points=[
                    models.PointStruct(
                        id=1,
                        vector=[1.0, 2.0, 3.0, 4.0],
                        payload={},
                    ),
                ]
            )
        ),
        models.UpdateVectorsOperation(
            update_vectors=models.UpdateVectors(
                points=[
                    models.PointVectors(
                        id=1,
                        vector=[1.0, 2.0, 3.0, 4.0],
                    )
                ]
            )
        ),
        models.SetPayloadOperation(
            set_payload=models.SetPayload(
                payload={
                    "test_payload_2": 2,
                    "test_payload_3": 3,
                },
                points=[1],
            )
        ),
    ],
)

```

```java
import java.util.List;
import java.util.Map;

import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;

import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

import io.qdrant.client.grpc.Points.PointStruct;
import io.qdrant.client.grpc.Points.PointVectors;
import io.qdrant.client.grpc.Points.PointsIdsList;
import io.qdrant.client.grpc.Points.PointsSelector;
import io.qdrant.client.grpc.Points.PointsUpdateOperation;
import io.qdrant.client.grpc.Points.PointsUpdateOperation.PointStructList;
import io.qdrant.client.grpc.Points.PointsUpdateOperation.SetPayload;
import io.qdrant.client.grpc.Points.PointsUpdateOperation.UpdateVectors;

QdrantClient client = new QdrantClient(
                QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .batchUpdateAsync(
        "{collection_name}",
        List.of(
            PointsUpdateOperation.newBuilder()
            .setUpsert(
                PointStructList.newBuilder()
                .addPoints(
                    PointStruct.newBuilder()
                    .setId(id(1))
                    .setVectors(vectors(
                        1.0 f,
                        2.0 f,
                        3.0 f,
                        4.0 f))
                    .build())
                .build())
            .build(),
            PointsUpdateOperation.newBuilder()
            .setUpdateVectors(
                UpdateVectors.newBuilder()
                .addPoints(
                    PointVectors.newBuilder()
                    .setId(id(1))
                    .setVectors(vectors(
                        1.0 f,
                        2.0 f,
                        3.0 f,
                        4.0 f))
                    .build())
                .build())
            .build(),
            PointsUpdateOperation.newBuilder()
            .setSetPayload(
                SetPayload.newBuilder()
                .setPointsSelector(
                    PointsSelector.newBuilder()
                    .setPoints(PointsIdsList
                        .newBuilder()
                        .addIds(id(1))
                        .build())
                    .build())
                .putAllPayload(
                    Map.of("test_payload_2",
                        value(2),
                        "test_payload_3",
                        value(3)))
                .build())
            .build()))
    .get();

```

```go
package client

import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

func batchUpdate() {
	client, err := qdrant.NewClient(&qdrant.Config{
		Host: "localhost",
		Port: 6334,
	})
	if err != nil {
		panic(err)
	}

	_, err = client.UpdateBatch(context.Background(), &qdrant.UpdateBatchPoints{
		CollectionName: "{collection_name}",
		Operations: []*qdrant.PointsUpdateOperation{
			qdrant.NewPointsUpdateUpsert(&qdrant.PointsUpdateOperation_PointStructList{
				Points: []*qdrant.PointStruct{{
					Id:      qdrant.NewIDNum(1),
					Vectors: qdrant.NewVectors(1.0, 2.0, 3.0, 4.0),
				}},
			}),
			qdrant.NewPointsUpdateUpdateVectors(&qdrant.PointsUpdateOperation_UpdateVectors{
				Points: []*qdrant.PointVectors{
					{
						Id:      qdrant.NewIDNum(1),
						Vectors: qdrant.NewVectors(0.1, 0.2, 0.3, 0.4),
					},
				},
			}),
			qdrant.NewPointsUpdateSetPayload(&qdrant.PointsUpdateOperation_SetPayload{
				PointsSelector: qdrant.NewPointsSelector(qdrant.NewIDNum(1)),
				Payload: qdrant.NewValueMap(map[string]any{
					"test_payload_2": 2,
					"test_payload_3": 3,
				}),
			}),
		},
	})
	if err != nil {
		panic(err)
	}
}

```

```typescript
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.batchUpdate("{collection_name}", {
    operations: [
        {
            upsert: {
                points: [
                    {
                        id: 1,
                        vector: [1.0, 2.0, 3.0, 4.0],
                        payload: {},
                    },
                ],
            },
        },
        {
            update_vectors: {
                points: [
                    {
                        id: 1,
                        vector: [1.0, 2.0, 3.0, 4.0],
                    },
                ],
            },
        },
        {
            set_payload: {
                payload: {
                    test_payload_2: 2,
                    test_payload_3: 3,
                },
                points: [1],
            },
        },
    ],
});

```

```rust
use qdrant_client::qdrant::{
    points_selector::PointsSelectorOneOf,
    points_update_operation::{
        Operation, OverwritePayload, PointStructList, UpdateVectors,
    },
    PointStruct, PointVectors, PointsIdsList, PointsSelector, PointsUpdateOperation,
    UpdateBatchPointsBuilder,
};
use qdrant_client::{Qdrant, Payload};
use serde_json::json;
use std::collections::HashMap;

let client = Qdrant::from_url("http://localhost:6334").build()?;

client
    .update_points_batch(
        UpdateBatchPointsBuilder::new(
            "{collection_name}",
            vec![
                PointsUpdateOperation {
                    operation: Some(Operation::Upsert(PointStructList {
                        points: vec![PointStruct::new(
                            1,
                            vec![1.0, 2.0, 3.0, 4.0],
                            Payload::try_from(json!({})).unwrap(),
                        )],
                        ..Default::default()
                    })),
                },
                PointsUpdateOperation {
                    operation: Some(Operation::UpdateVectors(UpdateVectors {
                        points: vec![PointVectors {
                            id: Some(1.into()),
                            vectors: Some(vec![1.0, 2.0, 3.0, 4.0].into()),
                        }],
                        ..Default::default()
                    })),
                },
                PointsUpdateOperation {
                    operation: Some(Operation::OverwritePayload(OverwritePayload {
                        points_selector: Some(PointsSelector {
                            points_selector_one_of: Some(PointsSelectorOneOf::Points(
                                PointsIdsList {
                                    ids: vec![1.into()],
                                },
                            )),
                        }),
                        payload: HashMap::from([("test_payload".to_string(), 1.into())]),
                        ..Default::default()
                    })),
                },
            ],
        )
        .wait(true),
    )
    .await?;

```

```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.UpdateBatchAsync(
    "{collection_name}",
    [
        new()
        {
            Upsert = new()
            {
                Points =
                {
                    new PointStruct { Id = 1, Vectors = new[] { 0.9f, 0.1f, 0.1f } },
                }
            }
        },
        new()
        {
            UpdateVectors = new()
            {
                Points =
                {
                    new PointVectors { Id = 1, Vectors = new[] { 0.9f, 0.1f, 0.1f } },
                }
            }
        },
        new()
        {
            SetPayload = new()
            {
                PointsSelector = new PointsSelector { Points = new PointsIdsList { Ids = { 1 } } },
                Payload = { ["test_payload_2"] = 2, ["test_payload_3"] = 3 }
            }
        }
    ]
);

```

```ruby
require 'uri'
require 'net/http'

url = URI("http://localhost:6333/collections/collection_name/points/batch")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Post.new(url)
request["api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"operations\": [\n    {\n      \"delete\": {\n        \"filter\": {}\n      }\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'http://localhost:6333/collections/collection_name/points/batch', [
  'body' => '{
  "operations": [
    {
      "delete": {
        "filter": {}
      }
    }
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```swift
import Foundation

let headers = [
  "api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["operations": [["delete": ["filter": []]]]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "http://localhost:6333/collections/collection_name/points/batch")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```