> ## Documentation Index
> Fetch the complete documentation index at: https://developer.plugsurfing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Geosearch

Search for EV charging locations by radius, route, or batch. Get detailed location information including connectors, availability, pricing and more.

## Overview

The Geosearch endpoint provides multiple ways to find and retrieve charging location information:

* **Radius search**: Find chargers within a specified distance from a point
* **Rectangle search**: Find chargers within a specified rectangle defined by two diagonal points
* **Route search**: Search for chargers along a travel route
* **Batch retrieval**: Get all locations for full data synchronization

Use the search endpoints for discovery, map pins, and list views. They return location, connector, and availability data, but they do not include prices. When a user opens a location detail view or selects a connector, call [Get location by id](/reference/getLocationById) to retrieve full details including prices.

EMP integrations use equivalent endpoints under `/emp/v1`. When making EMP geosearch requests for a specific fleet, pass `fleetId` as an optional query parameter on radius, rectangle, route, and location-by-id requests.

For each charging location, you can access:

* Available connectors and specifications
* Real-time availability status
* Opening hours
* Operator details
* Physical location and directions

## Radius search

[**API Reference**](/reference/searchLocationsByRadius)

Radius search helps users find charging locations near a specific point. This is useful for:

* Finding chargers near the user's current location
* Discovering charging options in a particular area
* Analyzing charging infrastructure density

### Basic usage

Use an empty JSON body when you want to show all locations near a coordinate without filters:

```bash theme={null}
curl --request POST \
  --url 'https://drive-api-stage.plugsurfing.com/drive/v1/geosearch/radius?latitude=59.33&longitude=18.07&distance=5000' \
  --header "X-API-Key: $API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{}'
```

The center point, distance, limit, and aggregation settings are query parameters. The JSON body is used only for optional filters.

```json theme={null}
POST /v1/geosearch/radius?latitude=52.3&longitude=4.7

{
  "filters": {
    "locationStatuses": ["AVAILABLE"]
  }
}
```

This will return up to 300 available charging locations within 3000 meters of the specified point.

For EMP fleet context, use the EMP endpoint and add `fleetId` to the query string:

```json theme={null}
POST /emp/v1/geosearch/radius?latitude=52.3&longitude=4.7&fleetId=acme-corp-001
```

### Result ordering

Results are sorted by proximity to the search center point (nearest first). You can rely on this ordering without additional client-side sorting.

### Advanced search settings

#### 1. Adjusting search area

* Use the `distance` parameter to change the search radius (in meters)
* Larger radius will return more results but might lead to a slower response
* For better performance with large radius searches, consider using aggregation

#### 2. Filtering results

You can narrow down results using various filters:

```json theme={null}
{
  "filters": {
    "locationStatuses": ["AVAILABLE"], // Only show available chargers
    "powerType": "DC", // Only DC chargers
    "power": 50000, // Min 50kW power
    "open247": true // Only 24/7 locations
  }
}
```

#### 3. Using aggregation

For large areas, you can use aggregation to get clustered results:

```json theme={null}
POST /v1/geosearch/radius?latitude=58.5&longitude=14.75&aggregate=true&aggregationPrecision=5

{
  "filters": {
    "powerType": "DC"
  }
}
```

This returns clusters of charging locations instead of individual points, making it ideal for:

* Map overview displays
* Understanding charging density in large areas
* Faster response times for large radius searches

## Rectangle search

[**API Reference**](/reference/searchLocationsByRectangle)

Rectangle search helps users find charging locations in a rectangle defined by two diagonal points. This is useful for displaying chargers on a map. Examples of this includes drivers app, in car map or on a web page.

### Basic usage

```json theme={null}
POST /v1/geosearch/rectangle?topLatitude=52.3&bottomLatitude=51.3&leftLongitude=4.7&rightLongitude=5.1

{
  "filters": {
    ...
  }
}
```

This will return up to 300 available charging locations within the defined rectangle.

For EMP fleet context, add `fleetId` to the query string:

```json theme={null}
POST /emp/v1/geosearch/rectangle?topLatitude=52.3&bottomLatitude=51.3&leftLongitude=4.7&rightLongitude=5.1&fleetId=acme-corp-001
```

### Advanced search settings

All advanced search settings from [Radius Search](#radius-search) are available for this request as well.

## Route search

[**API Reference**](/reference/searchLocationsByRoute)

Route search helps find chargers along a route by passing a set of points that this route consists of. This is useful to let the user find convenient charging stops during their trip.

For EMP fleet context, add `fleetId` to the query string:

```json theme={null}
POST /emp/v1/geosearch/route?fleetId=acme-corp-001
```

### Example request:

```json theme={null}
{
  "points": [
    {
      "latitude": "58.1",
      "longitude": "13.3"
    },
    {
      "latitude": "58.0",
      "longitude": "13.295"
    }
  ],
  "filters": {
    "connectorStandards": ["3PinSquare"],
    "locationStatuses": ["AVAILABLE"],
    "capabilities": ["REMOTE_START_STOP_CAPABLE"],
    "power": 20000,
    "powerType": "AC",
    "open247": true
  }
}
```

## Location by id

[**API Reference**](/reference/getLocationById)

This endpoint returns all details for a given location, and unlike the other geosearch endpoints, it includes prices.

### Prices

When retrieving location details, it is possible to specify the user, charging key, or fleet for which prices should be looked up (if no parameter is provided, default prices are returned). Standard Drive requests can specify `userId` or `keyIdentifier`. EMP requests can specify `keyIdentifier` or `fleetId`; only one pricing-context parameter can be provided in a single request.

```json theme={null}
GET /emp/v1/locations/{locationId}?fleetId=acme-corp-001
```

In some rare cases, the price might be absent. If the price is not available, it is recommended to display a message to the end user such as "Price temporarily unavailable".

#### Price object model

* **id** (string) - Price id
* **description** (string) - Human-readable price description, e.g. `€ 0.56/kWh`
* **currency** (string) - Three-letter currency code ([ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) format)
* **priceIncludesVat** (boolean) - Indicates whether the price includes VAT or not (same meaning as for the CDR object)
* **vatRate** (number) - The VAT rate that is applied to the price (in case `priceIncludesVat=true`) or the VAT rate that should be applied to the price (in case `priceIncludesVat=false`)
* **elements** (array, required) - Possible prices for that connector, depending on restrictions
  * **price\_components** (array)
    * **price** (number) - Cost in the currency stated above. VAT is included. Decimal number. For example, if currency is EUR and price is 1.10, the cost is €1.10. More information on pricing can be found below
    * **type** (string/enum) - Can be one of TIME, ENERGY, FLAT, CAPPED, PARKING\_TIME, CONGESTION\_TIME
    * **step\_size** (number) - The smallest unit of usage that will be billed. Unit: seconds for `TIME`, `PARKING_TIME`, and `CONGESTION_TIME`; watt-hours (Wh) for `ENERGY`; ignored for `FLAT` and `CAPPED`. Check explanation below
  * **restrictions** (object) - Each restriction can contain one or more of the following properties (it can also be empty):
    * **start\_time** (string) - example: `11:30` - local time when this price element starts applying
    * **end\_time** (string) - example: `21:00` - local time when this price element ends applying
    * **day\_of\_week** (array of string/enum) - possible values: \[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY].
    * **min\_duration** (number) - minimum duration (in seconds) to apply this price element
    * **max\_duration** (number)
    * **min\_kwh** (number) - total power (in kWh) charged throughout the session to apply this price element
    * **max\_kwh** (number)
    * **min\_vehicle\_soc** (number) - minimum vehicle state of charge in percentage, valid for vehicle state of charge from x%
    * **max\_vehicle\_soc** (number) - maximum vehicle state of charge in percentage, valid for vehicle state of charge up to x%
    * **min\_congestion\_threshold** (number) - minimum congestion threshold of the location, congestion fee will apply from valid x%
    * **max\_congestion\_threshold** (number) - maximum congestion threshold of the location, congestion fee will apply to valid x%

#### Explanation

The **first** price element that matches all restrictions is selected. Then, the components from that element are combined to calculate the final price.

Units for `price` and `step_size` per type:

| **Type** | **Price Unit** | **Step Size Unit** |
| - | - | - |
| TIME | hour | seconds |
| PARKING\_TIME | hour | seconds |
| CONGESTION\_TIME | hour | seconds |
| ENERGY | kWh | Wh |
| FLAT | session | ignored (N/A) |
| CAPPED | session | ignored (N/A) |

#### How step\_size works

Example:

```text theme={null}
{
  "type": "TIME",
  "step_size": 300,
  "price_per_hour": 6.00
}
```

When type is `TIME`, step\_size is in seconds (see table above). 300 seconds equals 5 minutes, so in this case the customer will be billed in 5-minutes blocks.<br />If the user charges for 6 minutes, they will be billed for \_10 minutes\_ (2 blocks of 300 seconds). The `price` is specified for a full hour. In this example, the price is 6.00€. Since 10 minutes is one-sixth of an hour, the user will be charged €1.00 (i.e., €6.00 ÷ 6 = €1.00).

The price elements are defined in the OCPI tariff standard, you can find examples [here](https://github.com/ocpi/ocpi/blob/2.2.1/mod_tariffs.asciidoc#142-pricecomponent-class).

## Locations batch

[**API Reference**](/reference/getLocationsBatch)

This endpoint allows you to retrieve all available locations one page at a time.<br />Locations are returned sorted by their last update timestamp (`last_updated` field) in ascending order, meaning the most recently updated location appears last in the result.

The most efficient way to use this endpoint is to:

1. Perform a **FULL PULL**:
   1. Issue a request to `/v1/locations/batch` to retrieve the first page of locations along with a `cursor`.
   2. Continue requesting more locations using `/v1/locations/batch?cursor=<cursor_from_previous_request>`, where `cursor_from_previous_request` is the cursor returned by the previous request.
   3. Repeat until the response does not include a new cursor, indicating there are no more locations to retrieve.
2. After the **FULL PULL** (1), perform regular **DELTA PULLS** by specifying the `last_updated` parameter: `/v1/locations/batch?last_updated=2024-05-27T10:44:48.123Z`. The endpoint will only return locations that have been updated after `last_updated`. The pagination logic (cursor) should be used for DELTA PULLs as well.
   1. Since the locations are returned in ascending order, you can record the `last_updated` value of the last location in the last page. That is the point in time when you last were in-sync with location data. You can pass that value as `last_updated` parameter to the next DELTA PULL. This will guarantee you always receive all updates.

A **FULL PULL** is required when setting up the integration and should also be performed regularly to ensure complete synchronization. While **DELTA PULLs** capture updates efficiently, periodic **FULL PULLs** allow you to detect locations that no longer exist and mark them as hidden. One approach is to hide locations that have a `last_updated` timestamp older than the latest FULL PULL.

If a failure occurs during a PULL process, you can use the `cursor` to resume. For instance, if the process crashes after 500 pages, you can restart from the last successfully processed page by using the last returned cursor.

## Operators list

[**API Reference**](/reference/listOperators)

Drive API provides access to a list of Charging Point Operators (CPOs) whose chargers are available through the geosearch endpoints. This is useful for:

* Displaying operator names in your UI
* Filtering geosearch results by specific operators

The first page should be fetched without providing any cursor. Use the cursor provided in the response of each page to get the next page. The last page has no cursor.

## Aggregation

If the 'aggregate' parameter is set to true, but an aggregation rectangle will contain only one location, then it will end up in the **locations** array. This means both **locations** and **aggregates** arrays can be filled. If there is only one location in the aggregation rectangle, then it will end up in **locations** array.

If 'aggregate' parameter is absent or false, then **aggregates** array will not appear in the results at all.

Here is a table describing the sizes of a rectangles used for each aggregation level:

| Value | Meaning |
| - | - |
| 2 | 1,252.3km x 624.1km |
| 3 | 156.5km x 156km |
| 4 | 39.1km x 19.5km |
| 5 | 4.9km x 4.9km |
| 6 | 1.2km x 609.4m |
| 7 | 152.9m x 152.4m |
| 8 | 38.2m x 19m |
| 9 | 4.8m x 4.8m |

> 📘
>
> Aggregation can not be selected if `openNow` filter is set to true. Doing so returns`400`.

## Filtering

Important considerations when filtering:

* A location is included if ANY of its connectors match the filter criteria
* Results include ALL connectors at matching locations
* Client-side filtering may be needed for specific connectors
* Multiple filters can be combined
* Operator filtering takes precedence over exclusions
* Connector `power` values are expressed in watts. For display, divide by 1000 to show kW, for example `50000` = `50 kW`.

When using filters (i.e. location status filter), the result will contain each location that have **at least one charger** with this status. This means that when you enter `AVAILABLE` in the filter, you might get a location with 5 chargers, out of which only one will have status `AVAILABLE`.<br />Chargers with other statuses will have to be filtered out on your side.

Same rule applies to all other filters relating to chargers or connector: if even one charger/connector fulfills the filtering, then the whole location with all chargers and connectors will be returned.

### Filtering on operator ids

This array of integer ids represent a filter where only the chargers from the operators provided will be returned.<br />If this value is provided it will ignore `excludedOperatorIds` if also provided.

### Excluded operator ids

This array of integer ids represent a filter where the chargers belonging to the operators provided will be excluded from the results. If `operatorIds` are provided, this array will be ignored.

### Filtering EVSE IDs

You can filter locations by their EVSE IDs using partial matching. The filter works by breaking down the EVSE ID into parts and matching those parts:

For example, given an EVSE ID `IE*ION*E406304`:

✅ These filters will match:

* `IE` (matches first part)
* `ION` (matches middle part)
* `IE*ION` (matches beginning)
* `*ION*` (matches middle)

❌ These filters won't match:

* `ION*E4` (because `E4` is only part of `E406304`)
* `406` (because it's only part of a segment)

Key points:

* Special characters like `*` act as separators
* Each filter must match a complete segment
* When using multiple EVSE ID filters, a match on any filter will include the location

This filtering is useful when you want to find chargers from specific networks or locations that follow known ID patterns.

### Connector standards

The API supports a wide range of connector types:

* Standard AC connectors (Type 1, Type 2, etc.)
* DC fast charging (`Combo` for CCS and `CHADEMO`)
* Tesla connectors
* Industrial and domestic sockets

Unrecognized connector standards should be mapped to UNKNOWN type.

| Standard | Comment |
| - | - |
| 3PinSquare | Same as DOMESTIC\_G |
| Cee2Poles | Same as IEC\_60309\_2\_single\_16 |
| CeeBlue | Same as IEC\_60309\_2\_single\_16 |
| CeePlus | Same as IEC\_60309\_2\_three\_16 |
| CeeRed | Same as IEC\_60309\_2\_three\_32 |
| Combo | Use this value for CCS connectors / IEC\_62196\_T2\_COMBO |
| Marechal | Same as IEC\_60309\_2\_single\_16 |
| Nema5 | Same as DOMESTIC\_B |
| Scame | Same as IEC\_62196\_T3C |
| Type1 | Same as IEC\_62196\_T1 |
| Type2 | Same as IEC\_62196\_T2 |
| Type3 | Same as IEC\_62196\_T3A |
| TypeE | Same as DOMESTIC\_E |
| Schuko | Same as DOMESTIC\_F |
| T13 | Same as DOMESTIC\_J |
| T15 | Same as DOMESTIC\_J |
| T23 | Same as DOMESTIC\_J |
| CHADEMO | Preferred value. `Chademo` is kept as a legacy alias. |
| DOMESTIC\_A | Nema5, NEMA 1-15, 2 pins |
| DOMESTIC\_B | Nema5, NEMA 5-15, 3 pins |
| DOMESTIC\_C | CEE 7/17, 2 pins |
| DOMESTIC\_D | CeeBlue, 3 pin |
| DOMESTIC\_E | Schuko, CEE 7/5 3 pins |
| DOMESTIC\_F | Schuko, CEE 7/4, 3 pins |
| DOMESTIC\_G | '3PinSquare', BS 1363, Commonwealth, 3 pins |
| DOMESTIC\_H | SI-32, 3 pins |
| DOMESTIC\_I | AS 3112, 3 pins |
| DOMESTIC\_J | T23, SEV 1011, 3 pins |
| DOMESTIC\_K | DS 60884-2-D1, 3 pins |
| DOMESTIC\_L | CEI 23-16-VII, 3 pins |
| IEC\_60309\_2\_single\_16 | Industrial Connector single phase 16 Amperes (usually blue) |
| IEC\_60309\_2\_three\_16 | Industrial Connector three phase 16 Amperes (usually red) |
| IEC\_60309\_2\_three\_32 | Industrial Connector three phase 32 Amperes (usually red) |
| IEC\_60309\_2\_three\_64 | Industrial Connector three phase 64 Amperes (usually red) |
| IEC\_62196\_T1 | IEC 62196 Type 1 "SAE J1772" |
| IEC\_62196\_T1\_COMBO | Combo Type 1 based, DC |
| IEC\_62196\_T2 | IEC 62196 Type 2 "Mennekes" |
| IEC\_62196\_T2\_COMBO | Combo Type 2 based, DC |
| IEC\_62196\_T3A | IEC 62196 Type 3A |
| IEC\_62196\_T3C | IEC 62196 Type 3C "Scame" |
| TESLA\_R | Same as 'Tesla' – Connector "Roadster"-type (round, 4 pin) |
| TESLA\_S | Same as 'Tesla' |
| Tesla | |
| UNKNOWN | CPO didn't provide details for that connector |

### EVSE statuses

Understand these charger status values for proper handling and UI display:

| Status | Description |
| :- | :- |
| `AVAILABLE` | Ready for charging |
| `CHARGING` | Currently in use |
| `OCCUPIED` | Same as `CHARGING` |
| `RESERVED` | Should be treated the same as `CHARGING` |
| `BLOCKED` | Physically inaccessible |
| `INOPERATIVE` | Temporarily unavailable |
| `OUTOFORDER` | Broken or under maintenance |
| `PLANNED` | Not yet installed; should be hidden |
| `REMOVED` | No longer exists; should be hidden |
| `OFFLINE` | The charger has not sent any updates for an unknown reason |
| `UNKNOWN` | The status is unknown; it should not be shown as available |

### Summarizing location availability

Locations can contain multiple EVSEs with different statuses. For map pins and list summaries, derive a location-level status from the EVSE statuses:

| Status | Description |
| :- | :- |
| `available` | At least one EVSE is `AVAILABLE` |
| `mixed` | At least one EVSE is `AVAILABLE`, while at least one other EVSE is not available |
| `unavailable` | All EVSEs are unavailable, occupied, inoperative, or unknown |
| `unknown` | No EVSE status information is available |

For session start decisions, do not rely only on `AVAILABLE`; status updates can lag behind the physical charger state.

### Capabilities

The `capabilities` field is an array of strings. Unknown values should be accepted in case a new capability is introduced.

Only these capabilities can be taken into account to reliably enable or disable certain features on a charger:

* `REMOTE_START_STOP_CAPABLE`: indicates that the charger can be started remotely (see [Remote charging](/docs/drive-api/sessions#remote-charging))
* `PLUG_AND_CHARGE_CAPABLE`: indicates that the charger supports Plug\&Charge


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.