> Índice completo de la documentación: https://trackerintl.com/devs/llms.txt
> Esta página en HTML: https://trackerintl.com/devs/referencia/geocercas
> Estado: Parcial, revisada el 2026-10-05. Rutas y código confirmados en producción por diff. La respuesta 200 de dos operaciones solo se leyó del código y la forma de las rutas planificadas no se midió. No hay operaciones de creación o edición documentadas.

# Geocercas

Consulta tus geocercas y rutas planificadas, y averigua qué geocercas contienen un punto o la posición actual de un vehículo.

Esta sección es de **lectura**: lista geocercas y rutas, y responde en qué geocercas está un punto o un vehículo. Crear, editar o eliminar geocercas no está documentado.

- Una **geocerca** es un polígono o un círculo (`type`) que dibujó el usuario. Sus coordenadas llegan en `coordinates` como una **cadena JSON** que debes decodificar.
- Una **ruta planificada** es una línea de referencia dibujada por el usuario; no es el recorrido real. Para el recorrido real usa [Historial y rutas](/devs/referencia/historial-y-rutas).
- `point_in_geofences` y `devices_in_geofences` devuelven los **nombres** de las geocercas que contienen el punto. Tienen límites de peticiones por minuto (mira [Límites](/devs/limites)).

## Geocercas del usuario

**GET** `/api/get_geofences` · Estado: Verificado

Lista los polígonos y círculos propios del usuario. `coordinates` es una cadena JSON que debes decodificar. Si el usuario no tiene permiso, devuelve `items.geofences` vacío.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `search` | query | string | No |  |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS "https://plataforma.trackerintl.com/api/get_geofences" \
  -H "user-api-hash: TU_API_HASH"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const respuesta = await fetch(`${BASE_URL}/api/get_geofences`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/get_geofences",
    headers={"user-api-hash": API_HASH},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/get_geofences";
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | Respuesta correcta. |
| `401` | Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

| Campo (respuesta 200) | Tipo | Descripción |
|---|---|---|
| `items` | object |  |

Ejemplo de respuesta 200 (datos ficticios):

```json
{
  "items": {
    "geofences": [
      {
        "id": 301,
        "user_id": 1,
        "group_id": 0,
        "active": 1,
        "name": "Base ficticia",
        "coordinates": "[{\"lat\":-17.78,\"lng\":-63.19},{\"lat\":-17.78,\"lng\":-63.17},{\"lat\":-17.79,\"lng\":-63.17},{\"lat\":-17.79,\"lng\":-63.19}]",
        "polygon_color": "#d000df",
        "created_at": "2026-02-24 21:09:52",
        "updated_at": "2026-02-24 21:09:52",
        "type": "polygon",
        "radius": null,
        "center": null,
        "device_id": null,
        "speed_limit": 0,
        "diem_rate_id": null,
        "additional": null
      }
    ]
  }
}
```

### Verificación

Estado: Verificado. Revisado el 5 de octubre de 2026. Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción.

## Geocercas que contienen un punto

**GET** `/api/point_in_geofences` · Estado: Parcial

Devuelve los nombres de las geocercas del usuario que contienen el punto (`lat`, `lng`). Límite de 30 peticiones por minuto. Si faltan `lat` o `lng`, responde HTTP 200 con `{status: 0, errors}`; si el usuario no tiene geocercas, responde 404.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`. Límite de la plataforma: 30 peticiones por minuto.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `lat` | query | number | Sí | Latitud. |
| `lng` | query | number | Sí | Longitud. |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS -G "https://plataforma.trackerintl.com/api/point_in_geofences" \
  -H "user-api-hash: TU_API_HASH" \
  --data-urlencode "lat=-17.78" \
  --data-urlencode "lng=-63.18"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const params = new URLSearchParams({
  lat: "-17.78",
  lng: "-63.18",
});
const respuesta = await fetch(`${BASE_URL}/api/point_in_geofences?${params}`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/point_in_geofences",
    headers={"user-api-hash": API_HASH},
    params={"lat": "-17.78", "lng": "-63.18"},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/point_in_geofences?" . http_build_query(["lat" => "-17.78", "lng" => "-63.18"]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | OK, o error de validación con HTTP 200. |
| `401` | Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `404` | El usuario no tiene geocercas. |
| `429` | Límite de peticiones superado (inferido del comportamiento estándar; no medido). |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

Ejemplo de respuesta 200 (datos ficticios):

```json
{
  "status": 1,
  "zones": [
    "Base ficticia"
  ]
}
```

### Verificación

Estado: Parcial. Revisado el 5 de octubre de 2026. Ruta y código confirmados en producción. La validación y el límite de peticiones se midieron en un entorno de pruebas; la respuesta 200 solo se leyó del código porque ese entorno no podía calcularla.

## Geocercas que contienen la posición actual de un vehículo

**GET** `/api/devices_in_geofences` · Estado: Parcial

Igual que `point_in_geofences`, pero usa la última posición de un vehículo del usuario. Límite de 1800 peticiones por minuto. Responde 404 si el usuario no tiene geocercas.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`. Límite de la plataforma: 1800 peticiones por minuto.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `device_id` | query | integer | Sí | ID del vehículo (campo id de get_devices). |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS -G "https://plataforma.trackerintl.com/api/devices_in_geofences" \
  -H "user-api-hash: TU_API_HASH" \
  --data-urlencode "device_id=9001"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const params = new URLSearchParams({
  device_id: "9001",
});
const respuesta = await fetch(`${BASE_URL}/api/devices_in_geofences?${params}`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/devices_in_geofences",
    headers={"user-api-hash": API_HASH},
    params={"device_id": "9001"},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/devices_in_geofences?" . http_build_query(["device_id" => "9001"]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | Respuesta correcta. |
| `401` | Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `404` | El usuario no tiene geocercas. |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

| Campo (respuesta 200) | Tipo | Descripción |
|---|---|---|
| `status` |  |  |
| `zones` | array de string | Nombres de las geocercas que contienen el punto. |

Ejemplo de respuesta 200 (datos ficticios):

```json
{
  "status": 1,
  "zones": [
    "Base ficticia"
  ]
}
```

### Verificación

Estado: Parcial. Revisado el 5 de octubre de 2026. Ruta y código confirmados en producción. La respuesta 200 no se midió; se leyó del código.

## Rutas planificadas

**GET** `/api/get_routes` · Estado: Parcial

Lista las rutas de referencia que dibujó el usuario (no es el recorrido real), 500 por página. Requiere permiso para ver rutas.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `search` | query | string | No |  |
| `page` | query | integer | No | Número de página. |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS "https://plataforma.trackerintl.com/api/get_routes" \
  -H "user-api-hash: TU_API_HASH"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const respuesta = await fetch(`${BASE_URL}/api/get_routes`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/get_routes",
    headers={"user-api-hash": API_HASH},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/get_routes";
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | Respuesta correcta. |
| `401` | Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

| Campo (respuesta 200) | Tipo | Descripción |
|---|---|---|
| `data` | array de object |  |
| `pagination` | object |  |

Ejemplo de respuesta 200 (datos ficticios):

```json
{
  "data": [],
  "pagination": {
    "total": 0,
    "per_page": 500,
    "current_page": 1,
    "last_page": 1,
    "next_page_url": null,
    "prev_page_url": null
  }
}
```

### Verificación

Estado: Parcial. Revisado el 5 de octubre de 2026. Ruta confirmada en producción. La forma de `data[]` no se midió porque el entorno de pruebas no tenía rutas.
