HAMAPI is a callsign watchlist and notification service for APRS. It lets users subscribe to callsigns they want to monitor and receive periodic APRS message notifications when those callsigns are active on the network.
What it does:
- Users add callsigns to a personal watchlist via APRS messages to
HAMAPI - HAMAPI monitors all APRS traffic for watched callsigns
- When a watched callsign is heard, HAMAPI sends the subscriber a notification indicating the callsign, packet type, and time it was seen
- Notifications are rate-limited per subscriber — after one fires, the next is suppressed until a configurable interval has elapsed (default: 8 hours)
- On service start or new subscription, the first observed packet fires immediately so the subscriber knows the callsign is currently active
Use cases:
- Know when a friend's station comes on the air
- Monitor a repeater or digipeater's activity
- Track whether a remote station is still transmitting
- Get periodic confirmation that a watched station remains active
How it works:
Users interact with HAMAPI by sending standard APRS messages. HAMAPI acknowledges every command and maintains per-subscriber state in a database. Notifications are delivered as APRS messages with retry-until-ACK delivery.
| Command | Payload format | Description |
|---|---|---|
on^w |
CALL[,CALL2,...] [MINUTES] |
Watch callsign(s) with optional notify interval (min: 30, default: 480) |
on^u |
CALL[,CALL2,...] |
Unwatch callsign(s) |
on^cc |
OLDCALL,NEWCALL |
Change subscriber callsign (move watchlist to new callsign) |
on^e |
CALL[,CALL2,...] |
Enable specific watch entry |
on^d |
CALL[,CALL2,...] |
Disable specific watch entry |
on^+ |
(none) | Enable all notifications globally |
on^- |
(none) | Disable all notifications globally |
on^l |
(none) | List watched callsigns (server log only) |
on^q |
HH HH or off |
Set or clear quiet hours |
lb^ |
[CALLSIGN] |
Query last beacon position |
All commands use the cmd^payload format as the APRS message text:
WB4BOR>APRS,TCPIP*::HAMAPI :on^w KM6LYW,WB4BOR-11{42
cmd— command family prefix (onorlb)^— separatorpayload— command-specific arguments{42— APRS message ID (assigned by the sender's client)
HAMAPI addresses are padded to 9 characters per the APRS message spec:
HAMAPI (with trailing spaces).
When HAMAPI receives any valid command message that carries a message ID, it sends back an APRS ACK immediately upon receipt:
HAMAPI>APRS,TCPIP*::WB4BOR :ack42
The ACK is sent three times to guard against packet loss:
| Send | When |
|---|---|
| 1st | Immediately on receipt |
| 2nd | +2 minutes |
| 3rd | +4 minutes |
The ACK is the confirmation that the command was received and processed.
No separate response text is sent for on^ commands.
on^w CALLSIGN[,CALLSIGN2,...] [INTERVAL_MINUTES]
Add one or more callsigns to the subscriber's watchlist. HAMAPI will send a notification when any watched callsign is heard on APRS, subject to the configured notification interval.
CALLSIGN— one or more callsigns, comma-separated, case-insensitiveINTERVAL_MINUTES— optional integer; minimum minutes between periodic notifications for this callsign (default: 480 minutes / 8 hours if omitted)
The interval controls how frequently you are reminded that a callsign is active.
After a notification fires, the next one will not fire until at least
INTERVAL_MINUTES have elapsed — regardless of how many packets arrive in between.
Interval constraints:
| Input | Behaviour |
|---|---|
| Omitted | Default: 480 minutes (8 hours) |
0 to 29 |
Clamped to 30 minutes (minimum) |
30+ |
Used as-is |
Examples:
on^w KM6LYW <- default 480-minute (8-hour) interval
on^w KM6LYW 30 <- notify every 30 minutes
on^w KM6LYW 60 <- notify every hour
on^w KM6LYW 480 <- notify every 8 hours
on^w KM6LYW,WB4BOR-11 30 <- notify every 30 minutes for both
on^w KM6LYW ← default 480-minute (8-hour) interval on^w KM6LYW 30 ← notify every 30 minutes on^w KM6LYW 60 ← notify every hour on^w KM6LYW 480 ← notify every 8 hours on^w KM6LYW,WB4BOR-11 15 ← notify every 15 minutes for both
---
### Unwatch callsign
on^u CALLSIGN[,CALLSIGN2,...]
Remove one or more callsigns from the watchlist permanently. Accepts a single
callsign or a comma-separated list.
Examples:
on^u KM6LYW on^u KM6LYW,WB4BOR-11
---
### Change subscriber callsign
on^cc OLDCALLSIGN,NEWCALLSIGN
Change the subscriber's own callsign. All watchlist entries, notification
settings (interval, quiet hours), and enabled state are moved from the old
callsign to the new one. Future notifications will be delivered to `NEWCALLSIGN`.
Use this when you change your APRS station callsign (e.g. from `WB4BOR` to
`WB4BOR-1` when switching clients or SSIDs). Your watched callsigns remain
the same — only the delivery address changes.
Example:
on^cc WB4BOR,WB4BOR-1
After this command, notifications for KM6LYW, REPEAT, etc. are sent to
`WB4BOR-1` instead of `WB4BOR`.
---
### Enable / disable a specific watch entry
on^e CALLSIGN[,CALLSIGN2,...] — enable on^d CALLSIGN[,CALLSIGN2,...] — disable
Temporarily enable or disable notification for specific watched callsigns without
removing them from the watchlist.
Examples:
on^e KM6LYW on^d KM6LYW,WB4BOR-11
---
### Enable / disable all notifications
on^+ — enable all notifications globally on^- — disable all notifications globally
Global toggle that overrides all per-callsign settings. A `+` re-enables
everything; a `-` suppresses all outbound notifications.
---
### List watched callsigns
on^l
List all currently enabled watched callsigns for this subscriber. The list is
logged server-side; no APRS response is sent (ACK only).
---
### Quiet hours
on^q START_HOUR END_HOUR — set quiet hours on^q off — clear quiet hours
Suppress notifications during a daily window. Hours are integers 0-23 in the
subscriber's configured timezone (UTC if no timezone is set).
Supports overnight ranges (e.g. `22` to `06`).
Examples:
on^q 22 06 <- quiet from 10 PM to 6 AM on^q 00 08 <- quiet from midnight to 8 AM on^q off <- always notify
---
## `lb^` Command — Last Beacon Query
lb^[CALLSIGN]
Query the database for the most recent position packet from a callsign.
- If `CALLSIGN` is omitted, the sender's own callsign is used.
- SSID-style message IDs appended by some clients (e.g. `WB4BOR-11{LB6812`) are
stripped automatically.
Examples:
lb^ <- query sender's own last beacon lb^KM6LYW lb^WB4BOR-11
### Response format
HAMAPI>APRS,TCPIP*::WB4BOR :lb^CALLSIGN:LAT,LON,ALT,COURSE,SPEED,TIMESTAMP,SYMBOL{N
| Field | Description |
|-------------|------------------------------------------|
| `CALLSIGN` | Callsign that was queried |
| `LAT` | Latitude, decimal degrees (5 dp) |
| `LON` | Longitude, decimal degrees (5 dp) |
| `ALT` | Altitude, metres (0 decimal places) |
| `COURSE` | Course, degrees (0 decimal places) |
| `SPEED` | Speed, km/h (1 decimal place) |
| `TIMESTAMP` | Unix timestamp of the packet |
| `SYMBOL` | Two-character APRS symbol (`table`+`code`) |
Example response:
lb^KM6LYW:37.76900,-122.41940,15,90,0.0,1717258220,/>
If no position data is found for the callsign, no response is sent (ACK only).
---
## Outbound Notifications
When a watched callsign is heard on APRS, HAMAPI sends a notification to the
subscriber as a standard APRS message:
HAMAPI>APRS,TCPIP*::WB4BOR :on^KM6LYW via pos 18:05Z{N
### Notification payload format
on^ via HH:MMZ
| Field | Description |
|------------|-------------|
| `CALLSIGN` | The watched callsign whose packet triggered the notification |
| `TYPE` | Short label for the APRS packet type (see table below) |
| `HH:MM` | UTC time HAMAPI received the triggering packet (24-hour clock) |
| `Z` | Literal suffix indicating UTC |
### Packet type labels
| Label | APRS packet type |
|-------------|-----------------------------------------|
| `pos` | Position report |
| `mic-e` | Mic-E compressed position report |
| `msg` | APRS message |
| `wx` | Weather report |
| `status` | Status packet |
| `obj` | Object |
| `item` | Item |
| `telemetry` | Telemetry data or telemetry definition |
| `?` | Unknown / unparseable packet |
### Parsing for client implementors
The message text always matches this pattern:
on^ via HH:MMZ
Suggested parse steps:
1. Check that the text starts with `on^` — this identifies it as an online notification.
2. Strip the `on^` prefix.
3. Split on ` via ` (space-via-space) to separate `CALLSIGN` (left) from `TYPE_AND_TIME` (right).
4. Split `TYPE_AND_TIME` on the final space to get `TYPE` and `HH:MMZ`.
5. Strip the trailing `Z` from `HH:MMZ` and parse as `HH:MM` UTC.
6. Convert the UTC time to the user's local timezone for display.
**Display example:**
last seen at 11:05 AM via pos packet
### Notification timing
Notifications fire in two cases:
1. **Immediately** — on the first packet seen after:
- A user adds the callsign to their watchlist (`on^w`)
- The HAMAPI service restarts
2. **Periodically** — each time a packet arrives from the watched callsign
once at least `notify_interval_minutes` have elapsed since the last
notification was sent to that subscriber. The timer is per-subscriber
and resets only when a notification fires, not on every incoming packet.
### Delivery
Retry-until-ACK: HAMAPI sends the notification up to 3 times (immediately,
+2 min, +4 min) and stops as soon as the subscriber's client ACKs the message.
Outbound notifications are rate-limited to 1 packet per second.
---
## Position Beacon
HAMAPI transmits a position beacon hourly and on each reconnect to APRS-IS:
HAMAPI>APRS,TCPIP*:!4147.56NL12322.97W&http://aprschat.online
Position: Happy Camp, CA (41 47.56'N 123 22.97'W). Symbol: `\&` (gateway diamond).
---
## APRS-IS Connection
HAMAPI connects to the North America Tier 2 pool (`noam.aprs2.net:14580`) with
server-side filter `g/HAMAPI` so it receives only messages addressed to it.