Empezar
Autenticación
Cómo obtener tu user_api_hash, cómo enviarlo en cada petición y qué permisos concede, con ejemplos en cURL, JavaScript, Python y PHP.
Estado: Parcial · Revisada el 5 de octubre de 2026
Qué se verificó y cómo: Ruta y código confirmados en producción por diff. Los errores 401 y 422 se midieron en un entorno de pruebas; la respuesta 200 del inicio de sesión se lee del código y la caducidad del hash no se midió en producción.
La API usa un único tipo de credencial: el user_api_hash de un usuario de la plataforma. Lo obtienes una vez con tu correo y tu contraseña y lo envías en cada petición.
Cómo funciona #
POST /api/loginconemailypassworddevuelve eluser_api_hash.- En cada llamada siguiente envías ese valor en la cabecera
user-api-hash. - La plataforma resuelve a qué usuario pertenece el hash y aplica sus permisos.
Si tu plataforma lo tiene habilitado, el hash también puede consultarse en la ficha del cliente dentro del panel de administración.
Enviar la credencial #
| Forma | Cómo | Recomendación |
|---|---|---|
| Cabecera | user-api-hash: TU_API_HASH | Recomendada |
| Parámetro | ?user_api_hash=TU_API_HASH (query o cuerpo) | Evítala: las URL quedan en registros de acceso |
Authorization: Bearer no funciona en esta API.
Datos y permisos del usuario
cURL
curl -sS "https://plataforma.trackerintl.com/api/get_user_data" \
-H "user-api-hash: TU_API_HASH"JavaScript · Node.js 22
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";
const respuesta = await fetch(`${BASE_URL}/api/get_user_data`, {
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 3 con requests
import json
import requests
BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"
respuesta = requests.get(
f"{BASE_URL}/api/get_user_data",
headers={"user-api-hash": API_HASH},
timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))PHP · PHP 8 con cURL
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";
$url = $baseUrl . "/api/get_user_data";
$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";Caducidad del hash #
La caducidad no está medida en producción. Según la lectura del código, el hash no caduca por tiempo y se regenera cuando el usuario cambia su contraseña; al regenerarse, el valor anterior deja de servir. Hasta tener una medición real, trátalo como un dato por confirmar y prepara tu integración para volver a iniciar sesión si recibes un 401.
Qué permisos tiene el hash #
El hash concede los mismos permisos que la contraseña del usuario: no existen claves de solo lectura, claves por cliente ni alcances por módulo. Los permisos del usuario (ver, editar y eliminar por módulo) se aplican en cada petición, y GET /api/get_user_data te devuelve la matriz completa. Por eso te recomendamos:
- Crear un usuario dedicado a la integración, con permisos únicamente de "ver".
- Guardar el hash en un gestor de secretos o en variables de entorno, nunca en el código ni en el navegador de tus usuarios.
- No enviarlo en la URL.
Errores de autenticación #
| Respuesta | Causa probable | Qué hacer |
|---|---|---|
401 con {"status": 0, "message": "..."} | Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor | Verifica el hash; si cambió la contraseña, vuelve a iniciar sesión; si todo está bien, contacta a quien administra tu cuenta |
422 en el inicio de sesión | Faltan email o password | Envía ambos campos |
Consulta el detalle en Errores y los límites de intentos en Límites.
Operación de inicio de sesión #
Obtener el hash de API (user_api_hash) #
POST /api/login Parcial
Canjea correo y contraseña por el user_api_hash, la credencial que se envía en el resto de las peticiones. Acepta cuerpo JSON o formulario. Si el usuario aún no tiene hash, la plataforma lo genera en ese momento.
Autenticación. Sin autenticación. Límite de la plataforma: 60 peticiones por minuto.
- Según el código, el hash no caduca por tiempo y cambia cuando el usuario cambia su contraseña. No se midió en producción.
- Límite de 60 peticiones por minuto (valor por defecto del código; el valor de producción no está confirmado).
- El hash concede los mismos permisos que la contraseña del usuario. No existen claves de solo lectura ni por alcance.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
email | cuerpo | string | Sí | |
password | cuerpo | string | Sí |
Ejemplo de solicitud
cURL
curl -sS -X POST "https://plataforma.trackerintl.com/api/login" \
-H "Content-Type: application/json" \
-d '{"email":"demo@example.com","password":"TU_CONTRASENA"}'JavaScript · Node.js 22
const BASE_URL = "https://plataforma.trackerintl.com";
const respuesta = await fetch(`${BASE_URL}/api/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "demo@example.com", password: "TU_CONTRASENA" }),
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));Python · Python 3 con requests
import json
import requests
BASE_URL = "https://plataforma.trackerintl.com"
respuesta = requests.post(
f"{BASE_URL}/api/login",
json={"email": "demo@example.com", "password": "TU_CONTRASENA"},
timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))PHP · PHP 8 con cURL
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$url = $baseUrl . "/api/login";
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(["email" => "demo@example.com", "password" => "TU_CONTRASENA"]),
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
]);
$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}. |
422 | Faltan email/password. Forma {status:0,errors:{campo:[..]}} (sin statusCode). |
429 | Límite de peticiones superado (inferido del comportamiento estándar; no medido). |
| Campo (respuesta 200) | Tipo | Descripción |
|---|---|---|
status | ||
user_api_hash | string | Credencial de la API. Larga vida: solo cambia si se cambia la contraseña del usuario. |
permissions | object |
Ejemplo de respuesta 200 (datos ficticios)
{
"status": 1,
"user_api_hash": "TU_API_HASH",
"permissions": {
"devices": {
"view": true,
"edit": false,
"remove": false
},
"alerts": {
"view": true,
"edit": false,
"remove": false
},
"events": {
"view": true,
"edit": false,
"remove": false
},
"geofences": {
"view": true,
"edit": false,
"remove": false
},
"routes": {
"view": true,
"edit": false,
"remove": false
},
"reports": {
"view": true,
"edit": false,
"remove": false
},
"history": {
"view": true,
"edit": false,
"remove": false
},
"send_command": {
"view": false,
"edit": false,
"remove": false
}
}
}Verificación
Estado: Parcial. Revisado el 5 de octubre de 2026. Ruta confirmada en producción y código idéntico al verificado. Los errores 401 y 422 se midieron en un entorno de pruebas; la respuesta 200 se lee del código porque no se hizo un inicio de sesión real.