Ingesta de telemetría
Ingesta lotes de datos GPS y de sensores desde dispositivos de rastreo.
/apidev/v1/telemetryResumen
Acepta arreglos de puntos de datos GPS y de sensores desde dispositivos de rastreo. Usa un patrón fire-and-forget: el servidor valida el contenido enviado, devuelve 200 OK con un conteo de aceptados y procesa los datos de forma asíncrona en segundo plano.
Una respuesta exitosa confirma que los puntos fueron aceptados para su procesamiento, no que ya hayan sido persistidos.
Solicitud
Cuerpo
El cuerpo de la solicitud es un arreglo JSON de objetos de punto de telemetría:
| Campo | Tipo | Requerido | Longitud máxima | Descripción |
|---|---|---|---|---|
imei | string | Sí | 50 | Identificador IMEI del dispositivo |
eventcode | string | Sí | 20 | Código de evento; consultá la tabla Códigos de evento más abajo |
fix | boolean | Sí | — | Si el GPS tiene una posición válida |
datetime | string | Sí | 40 | Marca de tiempo de la lectura (ISO 8601, sin zona horaria) |
latitude | string | Sí | 25 | Latitud en grados decimales |
longitude | string | Sí | 25 | Longitud en grados decimales |
altitude | number | Sí | — | Altitud en metros |
speed | number | Sí | — | Velocidad en km/h |
heading | number | Sí | — | Rumbo en grados (0–360) |
satellites | integer | No | — | Cantidad de satélites GPS visibles |
ignition | boolean | No | — | Estado de la ignición |
accuracy | string | No | 30 | Precisión del GPS en metros |
odometer | string | No | 50 | Lectura del odómetro en km |
horometer | number | No | — | Lectura del horómetro |
address | string | No | 500 | Dirección obtenida por geocodificación inversa |
Códigos de evento
El campo eventcode debe ser uno de los siguientes valores:
| Código | Evento | Descripción |
|---|---|---|
101 | POSICION | Reporte de posición periódico |
113 | POSICION_STANDBY | Reporte de posición en modo de espera |
116 | BATTERY_LOW | Alerta de batería baja |
117 | EXCESO_VELOCIDAD | Límite de velocidad superado |
118 | IGNICION_ON | Ignición encendida |
119 | IGNICION_OFF | Ignición apagada |
120 | POWER_ON | Alimentación externa conectada |
121 | POWER_OFF | Alimentación externa desconectada |
122 | INPUT01_ON | Entrada 1 activada |
123 | INPUT01_OFF | Entrada 1 desactivada |
124 | INPUT02_ON | Entrada 2 activada |
125 | INPUT02_OFF | Entrada 2 desactivada |
126 | INPUT03_ON | Entrada 3 activada |
127 | INPUT03_OFF | Entrada 3 desactivada |
128 | OUTPUT01_ON | Salida 1 activada |
129 | OUTPUT01_OFF | Salida 1 desactivada |
130 | OUTPUT02_ON | Salida 2 activada |
131 | OUTPUT02_OFF | Salida 2 desactivada |
132 | OUTPUT03_ON | Salida 3 activada |
133 | OUTPUT03_OFF | Salida 3 desactivada |
149 | REMOLQUE_INICIO | Remolque enganchado |
150 | REMOLQUE_FIN | Remolque desenganchado |
151 | BATERIA_EXT_LOW | Batería externa baja |
152 | BATERIA_INT_LOW | Batería interna baja |
153 | POWER_UP | Encendido del dispositivo |
162 | COLISION | Colisión detectada |
163 | ACELERACIONBRUSCA | Aceleración brusca |
164 | FRENADOBRUSCO | Frenado brusco |
165 | GIROBRUSCO | Giro brusco |
Los campos desconocidos en el cuerpo son rechazados. Solo se aceptan los campos enumerados arriba; cualquier propiedad adicional provoca un VALIDATION_ERROR.
Ejemplos de código
- cURL
- JavaScript
- Python
curl -s -X POST "https://$TENANT/apidev/v1/telemetry" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '[
{
"imei": "352093081234567",
"eventcode": "101",
"fix": true,
"datetime": "2026-04-04T14:30:00",
"latitude": "-34.6037",
"longitude": "-58.3816",
"altitude": 25,
"speed": 45,
"heading": 180,
"satellites": 12,
"ignition": true,
"odometer": "125430",
"accuracy": "3.5"
},
{
"imei": "352093081234567",
"eventcode": "101",
"fix": true,
"datetime": "2026-04-04T14:30:30",
"latitude": "-34.6040",
"longitude": "-58.3820",
"altitude": 25,
"speed": 48,
"heading": 185
}
]'
const points = [
{
imei: "352093081234567",
eventcode: "101",
fix: true,
datetime: "2026-04-04T14:30:00",
latitude: "-34.6037",
longitude: "-58.3816",
altitude: 25,
speed: 45,
heading: 180,
satellites: 12,
ignition: true,
odometer: "125430",
accuracy: "3.5",
},
{
imei: "352093081234567",
eventcode: "101",
fix: true,
datetime: "2026-04-04T14:30:30",
latitude: "-34.6040",
longitude: "-58.3820",
altitude: 25,
speed: 48,
heading: 185,
},
];
const response = await fetch(`https://${TENANT}/apidev/v1/telemetry`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(points),
});
const { data } = await response.json();
console.log(`Accepted: ${data.accepted}, Rejected: ${data.rejected}`);
points = [
{
"imei": "352093081234567",
"eventcode": "101",
"fix": True,
"datetime": "2026-04-04T14:30:00",
"latitude": "-34.6037",
"longitude": "-58.3816",
"altitude": 25,
"speed": 45,
"heading": 180,
"satellites": 12,
"ignition": True,
"odometer": "125430",
"accuracy": "3.5",
},
{
"imei": "352093081234567",
"eventcode": "101",
"fix": True,
"datetime": "2026-04-04T14:30:30",
"latitude": "-34.6040",
"longitude": "-58.3820",
"altitude": 25,
"speed": 48,
"heading": 185,
},
]
response = requests.post(
f"https://{TENANT}/apidev/v1/telemetry",
headers={**headers, "Content-Type": "application/json"},
json=points,
)
result = response.json()
print(f"Accepted: {result['data']['accepted']}")
Respuesta
Éxito — 200 OK
| Campo | Tipo | Descripción |
|---|---|---|
success | boolean | true — puntos aceptados para procesamiento asíncrono |
data.accepted | integer | Cantidad de puntos de telemetría aceptados |
data.rejected | integer | Cantidad de puntos rechazados (actualmente siempre 0 cuando es exitoso) |
data.status | string | Estado del procesamiento ("OK") |
meta | object | Objeto vacío |
{
"success": true,
"data": {
"accepted": 2,
"rejected": 0,
"status": "OK"
},
"meta": {}
}
Un 200 OK confirma que los puntos pasaron la validación y fueron encolados. El procesamiento ocurre de forma asíncrona; es posible que los datos no se puedan consultar de inmediato mediante el endpoint Posición del dispositivo.
Límite de solicitudes
La telemetría usa un algoritmo de token bucket en dos niveles. Consultá Límites de solicitudes para la explicación completa.
| Parámetro | Global (por usuario) | Por IMEI |
|---|---|---|
| Capacidad del bucket | 180 tokens | 90 tokens |
| Tasa de recarga | 30 tokens/seg | 15 tokens/seg |
| Costo por solicitud | ceil(points / 20) tokens | ceil(points / 20) tokens |
Ejemplos:
- 1 punto = 1 token → podés enviar ~180 solicitudes de un solo punto antes de vaciar el bucket
- 100 puntos = 5 tokens → podés enviar ~36 lotes de 100 antes de vaciar el bucket
- Rendimiento sostenido: ~600 puntos/seg a nivel global, ~300 puntos/seg por dispositivo
Errores
| Código | HTTP | Descripción |
|---|---|---|
VALIDATION_ERROR | 400 | Campos inválidos o ausentes, propiedades desconocidas, o el cuerpo no es un arreglo |
UNAUTHORIZED | 401 | tenant / Authorization / X-API-Key ausente, inválido o expirado |
FORBIDDEN | 403 | El usuario no tiene APICLI_POST_TELEMETRY |
RATE_LIMITED | 429 | Token bucket agotado (global o por IMEI) |
INTERNAL_ERROR | 500 | Error inesperado del servidor durante la ingesta |
Buenas prácticas
- Agrupá tus puntos en lotes — enviá hasta 100 puntos por solicitud para una relación óptima entre rendimiento y costo en tokens
- Un solo IMEI por lote cuando sea posible — evita la contención del bucket por IMEI entre dispositivos
- Monitoreá los encabezados del límite de solicitudes — revisá
X-RateLimit-Remainingpara regular el ritmo antes de llegar al 429 - Marcas de tiempo sin zona horaria — enviá como
"2026-04-04T14:30:00", no como"2026-04-04T14:30:00Z" - GPS fix = false — el servidor acepta el punto pero las coordenadas pueden no ser confiables
Relacionado
- API de Dispositivos — Consultá las posiciones de los dispositivos tras la ingesta
- Límites de solicitudes — Detalles del algoritmo token bucket
- Autenticación — Modelo de autenticación dual JWT + clave de API