EasyTrack API reference

Every endpoint you can integrate into your own system or external app: authentication, trackers, real-time GPS positions, vehicles, geofences, agent assignments, alerts, reports and share-links.

Overview

The EasyTrack API is a JSON REST API hosted on Cloudflare (edge, EU region). All requests use HTTPS. Responses are application/json (except CSV/PDF exports). Real-time tracking data comes from Teltonika / FMC trackers and is available a few seconds after the server receives it.

Domainhttps://api.easytrack.ch
FormatJSON UTF-8
AuthBearer token (obtained via email OTP)
MethodsGET, POST, PUT, PATCH, DELETE
CORSEnabled (Access-Control-Allow-Origin: * on the main resources)

Base URL & formats

https://api.easytrack.ch

Every endpoint below is relative to this base. Example: GET /devices → https://api.easytrack.ch/devices.

Authentication

Almost every endpoint requires a Bearer token. You obtain the token in two steps: request an OTP code by email, then verify the code. Then add the Authorization header to every request:

Authorization: Bearer <your_token>
Content-Type: application/json
Without a valid token Protected routes return 401 with {"error":"Token manquant"} or {"error":"Session invalide ou expirée"}. Endpoints marked Public do not require a token.

Your first call

1 · Request a code

curl -X POST https://api.easytrack.ch/auth/request-code \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.ch","lang":"en"}'

2 · Verify the code and get the token

curl -X POST https://api.easytrack.ch/auth/verify-code \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.ch","code":"123456"}'
# => { "success": true, "token": "…", "expires_at": "…", "user": { … } }

3 · List your trackers

curl https://api.easytrack.ch/devices \
  -H "Authorization: Bearer <token>"

In JavaScript (fetch):

const res = await fetch("https://api.easytrack.ch/devices", {
  headers: { Authorization: `Bearer ${token}` }
});
const { devices } = await res.json();

Endpoint families

Authentication — login & session

POST /auth/request-code Public

Sends a 6-digit OTP code by email (or SMS).

Body

{
  "email": "you@example.ch",
  "lang":  "en"          // optional (fr, de, en, it…)
}

Response

{ "success": true, "message": "Code sent", "expires_in": 600 }
POST /auth/verify-code Public

Verifies the OTP and returns a Bearer token. If 2FA is enabled, returns requires_2fa.

Body

{ "email": "you@example.ch", "code": "123456" }

Response (no 2FA)

{
  "success": true,
  "token": "…",
  "expires_at": "2026-08-01T10:00:00.000Z",
  "user": { "id": 42, "email": "you@example.ch", "role": "client", "two_factor_enabled": false }
}

Response (2FA required)

{ "success": true, "requires_2fa": true, "pending_token": "…" }
POST /auth/verify-2fa Public

Completes login with the TOTP code (or a backup code) and the pending_token.

Body

{ "pending_token": "…", "code": "654321" }
POST /auth/magic-link Public

Sends a one-time login link by email.

Body

{ "email": "you@example.ch" }
GET /auth/me Bearer

Returns the user tied to the current token (useful to validate a session).

POST /auth/logout Bearer

Invalidates the current session (the token can no longer be used).

GET /auth/sessions Bearer

Lists the account's active sessions. DELETE /auth/sessions revokes the other sessions.

Authentication — 2FA & profile

MethodEndpointPurpose
GET/auth/profileGet the profile
PUT/auth/profileUpdate the profile (name, language…)
GET/auth/2fa/status2FA status
POST/auth/2fa/setupGenerate TOTP secret + QR
POST/auth/2fa/verifyEnable 2FA (validates a code)
POST/auth/2fa/disableDisable 2FA
POST/auth/2fa/backup-codesRegenerate backup codes
POST/auth/push-tokenRegister a push token (mobile)
DELETE/auth/push-tokenRemove a push token
GET/auth/notification-preferencesNotification preferences
PUT/auth/notification-preferencesUpdate preferences

Trackers (devices)

A device is a GPS tracker identified by its imei. The endpoints below only return the trackers on your account (and those shared with you).

GET /devices Bearer

Enriched list of your trackers: last position, battery, online status, linked vehicle, active agent, SIM backup.

Response (excerpt)

{
  "success": true,
  "source": "known_devices",
  "devices": [
    {
      "id": 12, "imei": "350612073912345", "name": "Truck 1",
      "status": "online",
      "last_latitude": 46.204, "last_longitude": 6.143,
      "last_speed": 0, "last_heading": 180, "last_battery": 87,
      "last_position_at": "2026-07-11 06:12:33",
      "vehicle_plate": "GE 123456", "vehicle_name": "Van",
      "device_type": "FMC003", "tracker_model": "FMC003",
      "fuel_level_percent": 64, "fuel_level_litres": 32.4,
      "odometer_km_real": 84520, "odometer_km_calculated": 84310,
      "consumption_l_per_100km": 7.4,
      "active_agent_name": null, "is_shared": false
    }
  ]
}
GET /devices/realtime Bearer

Real-time variant: latest raw values of each active tracker, ideal to refresh a map.

GET /devices/active-days Bearer

Days for which at least one of the given IMEIs has positions (useful for a date picker).

Query

ParamRequiredDescription
imeisyesComma-separated list of IMEIs
fromnoMin date YYYY-MM-DD
tonoMax date YYYY-MM-DD
GET /devices/imei/{imei} Bearer

Tracker details by IMEI + its last 50 positions.

GET /devices/{id} Bearer

Tracker details by internal ID + its last 50 positions.

POST /devices Bearer

Activates (registers) a tracker on your account by its IMEI.

Body

{ "imei": "350612073912345", "name": "Truck 1" }   // name optional
PUT /devices/{id} Bearer

Renames/activates a tracker and updates the linked vehicle (created if needed).

Body (all fields optional)

{
  "name": "Truck 1", "is_active": true,
  "vehicle_plate": "GE 123456", "vehicle_name": "Van",
  "vehicle_type": "van", "vehicle_model": "Ford Transit",
  "vehicle_color": "#2563eb", "vehicle_assigned_to": "John"
}
DELETE /devices/{id} Bearer

Removes a tracker from the account (linked positions and alerts cleaned up, vehicle unlinked).

GPS positions

GET /positions/latest Bearer

Last known position of each of your trackers (one row per device).

GET /positions Bearer

Stream of recent positions, filterable by IMEI.

Query

ParamDefaultDescription
imei—Filter on one tracker
limit100Max number of points
GET /positions/imei/{imei} Bearer

Position history of a tracker, with optional geocoded addresses.

Query

ParamDefaultDescription
limit100Max number of points
from—Min bound (server_timestamp)
to—Max bound
addresstruefalse to disable reverse geocoding
GET /positions/export Bearer

Paginated export of a tracker's raw history (5000 points per page).

Query

ParamRequiredDescription
imeiyesTracker to export
from/tonoTime range
pagenoPage index (0 by default)

Response

{ "success": true, "imei": "…", "page": 0, "page_size": 5000,
  "count": 5000, "has_more": true, "positions": [ … ] }
GET /positions/device/{id} Bearer

Positions of a tracker via its internal ID.

GET /positions/sim/{imei} Bearer

Fallback positions from cellular (SIM) location when GPS is unavailable.

POST /position Public

Position ingestion (called by trackers/gateways). Rarely useful for a client integration.

Position fields

FieldDescription
latitude, longitudeWGS84 coordinates
speedSpeed (km/h)
heading / angleHeading (degrees)
altitudeAltitude (m)
satellites, hdopGPS fix quality
ignition, movementIgnition / movement (0/1)
battery_level, gsm_signalBattery and network signal
server_timestampServer timestamp (YYYY-MM-DD HH:MM:SS, UTC)
odometerGPS odometer from the tracker, in metres
fuel_levelFuel level when the tracker sends it

OBD and vehicle telemetry

OBD trackers (FMC003 and the same family) send the latest onboard values. GET /devices already includes device_type and the summary below. GET /devices/imei/{imei}/obd returns every raw AVL value plus the same summary.

MethodEndpointPurpose
GET/devices/imei/{imei}/obdLatest OBD values and the summary
GET/devices/imei/{imei}/hours?from=&to=Ignition hours inside and outside the work schedule

Summary fields

FieldSource
device_typeTracker model on the account (FMC130, FMC003, …)
fuel_level_percentOBD fuel level, AVL 48
fuel_level_litresOBD fuel volume, AVL 390
odometer_km_realDashboard mileage, AVL 389
odometer_km_calculatedGPS odometer converted to kilometres
consumption_l_per_100kmFuel rate (AVL 60) divided by OBD speed (AVL 37), when speed is at least 5 km/h
hours_in_scheduleIgnition time inside the Zurich work schedule
hours_out_of_scheduleIgnition time outside that schedule

Other OBD values stay in values, keyed by Teltonika AVL id: VIN 256, RPM 36, coolant 32, engine load 31, throttle 41, fuel rate 60, DTC count 30, fault codes 281, hybrid battery 411 and battery consumption 412 (kWh/100 km).

The hours endpoint uses from and to as YYYY-MM-DD HH:MM:SS. Without a saved schedule, the whole day counts as inside.

Position export (GET /positions/export) returns the raw rows. In the manager, CSV and JSON exports let you choose which columns to keep. GeoJSON, GPX and KML always keep the geometry.

Vehicles

Vehicle record linked to a tracker (plate, model, color, assigned person).

MethodEndpointPurpose
GET/vehiclesList your vehicles
GET/vehicles/{id}Vehicle details
POST/vehiclesCreate a vehicle
PUT/vehicles/{id}Update a vehicle
DELETE/vehicles/{id}Delete a vehicle

Body (POST/PUT)

{
  "plate": "GE 123456", "name": "Van",
  "vehicle_type": "van", "vehicle_model": "Ford Transit",
  "color": "#2563eb", "device_id": 12, "assigned_to": "John"
}

Geofences

Circular zones, drawn polygons, or an official outline (country, region, municipality, city). Entry and exit can each raise an alert.

MethodEndpointPurpose
GET/geofencesList your zones
GET/geofences/{id}Zone details
POST/geofencesCreate a circle or a polygon
PUT/geofences/{id}Update a zone
DELETE/geofences/{id}Delete a zone
GET/geofences/places?kind=&q=Search a country, region, municipality or city
GET/geofences/places/geometryOfficial outline for the chosen place
GET/manager/geofencesZones saved from the manager (circle, polygon or place)

kind is country, region, commune or city. Pass the hit (source, osmId or layer + featureId) to the geometry endpoint. The rings are [lat, lng]. Save them as polygon.

Body (POST/PUT)

{
  "name": "Geneva depot",
  "latitude": 46.204, "longitude": 6.143, "radius": 150,
  "polygon": [[[6.14, 46.20], [6.16, 46.20], [6.16, 46.22], [6.14, 46.20]]],
  "type": "vehicle",
  "vehicle_id": 12,
  "color": "#ef4444",
  "alert_on_enter": true, "alert_on_exit": true,
  "description": "Parking zone"
}

A circle uses latitude, longitude and radius (metres). A polygon or a place outline uses polygon. Latitude and longitude are then optional: the centre is computed from the ring.

Agent assignments

Manage your agents (promoters/drivers) and the allocation of trackers to an agent for a session.

MethodEndpointPurpose
GET/assignments/agentsList agents
POST/assignments/agentsCreate an agent
PUT PATCH/assignments/agents/{id}Update an agent
DELETE/assignments/agents/{id}Delete an agent
GET/assignments/devices/{imei}/currentAgent currently assigned to a tracker
GET/assignments/devices/{imei}/historyAssignment history
POST/assignments/devices/{imei}/assignAssign an agent to a tracker
POST/assignments/devices/{imei}/unassignRelease the tracker

Alerts

Notification rules (low battery, speeding, zone enter/exit, etc.).

MethodEndpointPurpose
GET/manager/alertsList alerts
POST/manager/alertsCreate an alert
PUT/manager/alerts/{id}Update an alert
DELETE/manager/alerts/{id}Delete an alert

Share-links (public sharing)

Create temporary share links that let anyone follow certain trackers without an account.

MethodEndpointPurpose
GET/manager/share-linksList your links
POST/manager/share-linksCreate a link (IMEI + expiry)
PUT/manager/share-links/{id}Update / (de)activate
DELETE/manager/share-links/{id}Revoke a link

Reports

Scheduled reports (PDF) and tracking of their runs.

MethodEndpointPurpose
GET/manager/reportsList configured reports
POST/manager/reportsCreate a scheduled report
POST/manager/reports/autoconfigAutomatic configuration
PUT/manager/reports/{id}Update a report
DELETE/manager/reports/{id}Delete a report
POST/manager/reports/{id}/run-nowGenerate immediately
GET/manager/reports/{id}/runsRuns of a report
GET/manager/report-runsAll recent runs
GET/manager/report-configsList configs
POST/manager/report-configsCreate a config

Notifications & settings

MethodEndpointPurpose
GET/manager/notificationsList notifications
POST/manager/notifications/{id}/readMark as read
GET/manager/settingsAccount settings
PUT/manager/settingsUpdate settings
PUT/manager/profileUpdate the manager profile
GET/manager/geofencesGeofences (manager view)

Public sharing

GET /open/share/{token} Public

Resolves a share-link: returns the shared trackers/IMEIs and the expiry. No token required.

Response

{ "success": true, "devices": [ … ], "imeis": ["…"], "expires_at": "…" }

Conventions — JSON responses

Successful responses usually carry success: true and the resource (or a list).

{ "success": true, "devices": [ … ] }

Errors

Errors return an appropriate HTTP status and a { "error": "message" } body.

StatusMeaning
400Invalid request (missing parameter / format)
401Missing, invalid or expired token
403Access denied to this resource (e.g. another account's tracker)
404Resource or endpoint not found
500Server error

Pagination

Position lists are limited via limit. The history export (/positions/export) is paginated in pages of 5000 points: iterate over page while has_more is true.

Dates & time zones

Good to know Each account only sees its own trackers (and those explicitly shared). A call on an unauthorized IMEI returns 403. Keep the token server-side; do not expose it in a public front end.