Roadmap

Integrations.

Trail-Safe is meant to fit into the systems you already use — your smart home, your fitness tracker, your group chat. Home Assistant, webhooks and the developer SDK are live today; here's what's already here and what's coming next.

Home Assistant, webhooks & SDK live

Your API keys

A key grants read-only access to your positions (all family members on a family plan). Paste it into the Home Assistant integration.

Home Assistant setup

  1. Open HACS in Home Assistant, go to Integrations.
  2. Click Explore & Download Repositories, search for Trail-Safe GPS Tracker and install it.
  3. Restart Home Assistant.
  4. Go to Settings → Devices & Services → Add Integration and search for Trail-Safe GPS Tracker.
  5. Enter your server URL and paste an API key from above.
  6. Each family member appears as a device_tracker entity on your map.

The Home Assistant integration is a community project published under the Trail-Safe name — that is the name to search for, and it works with your Trail-Safe account.

Repository: JackEsBauer/trailsafe-homeassistant

Webhooks

Paid plans

Get a signed HTTPS request the moment something happens on your account — an SOS, a check-in, a zone crossing — and, if you turn it on, the positions of the watches on your map. Pipe it into your own dashboard, n8n, Zapier, a chat bot or anything that accepts a POST.

  1. Open your dashboard → Integrations → Webhooks and add your HTTPS URL.
  2. Copy the signing secret (whsec_…) — it is shown once.
  3. Pick the events you want, or leave “All activity events” on.
  4. Press Send test and check the delivery log.

Events

sos.raisedSomeone in your family raised an SOS
sos.sentYou raised an SOS
sos.responseSomeone responded to an SOS
check_in.receivedA family member checked in
check_in.sentYou checked in
zone.enteredA watch entered a home zone
zone.leftA watch left a home zone
waypoint.markedA waypoint was marked from a watch
family.inviteYou were invited to a family
family.member_leftA member left your family
trip.endedA trip you joined was ended
positionA watch you can see reported a new position (opt-in, at most every 5 minutes per watch)
pingSent by “Send test”

Payload

Every request is a POST with a JSON body of type, timestamp and data.

{
  "type": "sos.raised",
  "timestamp": "2026-09-14T19:02:11Z",
  "data": {
    "activity_id": 48213,
    "code": "sos_raised",
    "severity": "error",
    "title": "SOS from Sam",
    "body": "Sam raised an SOS near Refuge du Goûter"
  }
}
{
  "type": "position",
  "timestamp": "2026-09-14T19:05:40Z",
  "data": {
    "device_id": "pixel-watch-3-8f2c",
    "device_name": "Sam's Pixel Watch",
    "member_name": "Sam",
    "lat": 45.8508, "lng": 6.8127,
    "accuracy_m": 6, "altitude_m": 3817,
    "speed_mps": 0.9, "battery_pct": 71,
    "sos": false,
    "recorded_at": "2026-09-14T19:05:38Z"
  }
}

Verifying the signature

Requests are signed to the Standard Webhooks spec, so the official libraries for Node, Python, Go, PHP, Ruby, Java and more verify them out of the box. Three headers come with every request: webhook-id (the same on every retry — use it to ignore duplicates), webhook-timestamp and webhook-signature (v1, + base64 HMAC-SHA256 of id.timestamp.body).

// npm i standardwebhooks
import { Webhook } from 'standardwebhooks'

const wh = new Webhook(process.env.WEBHOOK_SECRET) // "whsec_…"
app.post('/hooks', express.raw({ type: 'application/json' }), (req, res) => {
  const event = wh.verify(req.body, req.headers) // throws if the signature is wrong
  res.sendStatus(204)                           // answer fast, work later
})
import base64, hashlib, hmac, time

def verify(secret: str, headers, body: bytes) -> bool:
    msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
    if abs(time.time() - int(ts)) > 300:
        return False  # replayed or stale
    key = base64.b64decode(secret.removeprefix("whsec_"))
    mac = hmac.new(key, f"{msg_id}.{ts}.".encode() + body, hashlib.sha256)
    expected = base64.b64encode(mac.digest()).decode()
    return any(hmac.compare_digest(expected, s.split(",", 1)[1])
               for s in headers["webhook-signature"].split())

Delivery

  • Answer with any 2xx within 15 seconds. Redirects are not followed.
  • Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h — seven attempts in all.
  • After 20 failures in a row the webhook is switched off and we email you. Fix it, send a test, and enable it again.
  • Only public https:// URLs are accepted, up to 50 webhooks per account.
  • If an endpoint falls more than 500 events behind, newer events for it are skipped until it catches up.
  • The delivery log in your dashboard keeps 7 days of requests, with the payload and the response code.

Developer SDK

Family Plus

Build your own apps on your family’s data: last known positions, location history, trails and recordings, zones and who is in them, the activity feed, and a live stream of positions and events (SOS, check-ins, zone arrivals). Read-only — the SDK can’t move, message or wake anyone.

  1. Open your dashboard → Integrations → Developers and create an SDK key (tsk_…). It is shown once.
  2. Your code trades the key at POST /api/sdk/v1/token for a bearer token (a JWT valid for 15 minutes).
  3. Call /api/sdk/v1/… with Authorization: Bearer <token>. The Go SDK does steps 2 and 3 for you.

Go

import paceguard "paceguard.io/sdk"

c := paceguard.New(os.Getenv("PACEGUARD_SDK_KEY"),
    paceguard.WithBaseURL("https://trail-safe.app"))

positions, err := c.Positions(ctx) // every family device's last fix

// live positions + activity; renews the token and reconnects by itself
err = c.Stream(ctx, paceguard.StreamOptions{}, func(ev paceguard.Event) error {
    fmt.Println(ev.Type)
    return nil
})

Python

import os, requests

BASE = "https://trail-safe.app"
tok = requests.post(f"{BASE}/api/sdk/v1/token",
    headers={"Authorization": f"Bearer {os.environ['PACEGUARD_SDK_KEY']}"}).json()["access_token"]

positions = requests.get(f"{BASE}/api/sdk/v1/positions",
    headers={"Authorization": f"Bearer {tok}"}).json()["positions"]

JavaScript works the same way with fetch; the dashboard shows a ready-to-copy example for Go, Python and JavaScript next to your key.

Endpoints

GET /api/sdk/v1/positionsLast known position of every family device
GET /api/sdk/v1/devicesWatches and phones you can see
GET /api/sdk/v1/devices/{id}/locationsLocation history (since, until, limit)
GET /api/sdk/v1/devices/{id}/trailsTrails of a device
GET /api/sdk/v1/tracksYour recordings; /tracks/{id}/geometry for the points
GET /api/sdk/v1/zonesHome, school and other zones, and who is in them
GET /api/sdk/v1/activityActivity feed: SOS, check-ins, arrivals
GET /api/sdk/v1/membersYour family
GET /api/sdk/v1/streamLive positions and activity (Server-Sent Events)

Limits

  • One SDK key per account, and one active session per key: a new token ends the previous one (session_replaced). Run one program per key.
  • One open live stream per account. The stream ends when its token expires; reconnect with a new one.
  • Optionally lock a key to your own IP addresses or networks under Integrations → Developers → Restrict to IPs; calls from anywhere else get ip_not_allowed.
  • Revoking the key, or leaving Family Plus, stops its tokens and its stream within a minute.
  • Responses never contain IP addresses of your devices.
  • Polling the SDK never wakes your family’s phones; only someone opening the map does.

Also on the list

Kids watch

Coming soon

Bring your child's kids watch onto the family map, with its position and battery — linked from the dashboard on Family plans, where you can also locate it, send it a message and change its alarms and settings.

Strava

Coming soon

Auto-publish completed hikes with the recorded track, elevation profile, and heart-rate trace.

Garmin Connect

Coming soon

Side-load fixes from a Garmin watch so you can use the hardware you already own.

Apple Health / Health Connect

Coming soon

Pull in vitals (resting HR, VO2 max) to give your hiking profile better baselines.

Slack / Discord

Coming soon

Post departure and arrival notices to a private channel for hiking groups and family threads.

IFTTT / Make

Coming soon

No-code triggers for the long tail — light a smart bulb when you start, send an SMS when you arrive.