Remote Actions
Send @@<otp>#<action> commands at another station from inside Messages
A Remote Action is the outbound side of the same
grammar described on the Actions page.
Where Actions defines what your station will run when an
@@-prefixed message arrives, Remote Actions lets you
send those messages at someone else’s station from
inside Messages — either by tapping a saved macro tile or by
typing a one-off command.
Both sides have to be set up. The receiving station must already have a matching Action defined; this page covers the sender side and walks through the credential copy-paste between the two.
Two sides, one secret
OTP-protected Actions use a shared Secret Key — the standard RFC 4648 base32 string a TOTP authenticator app consumes. The receiving station generates that Secret Key when the operator creates the credential on its Actions page; the sending station stores the same Secret Key in the Remote Actions drawer. From then on, both sides compute the same six-digit code from the wall clock and the receiver accepts it.
There is no key exchange protocol — operators copy and paste the Secret Key over a side channel they trust (signal, email, voice over the air, paper handoff). Treat it like an SSH key.
Same string, two sides. The value labelled
Secret Key in the receiver’s reveal panel and the
value labelled Secret Key in the sender’s
New Secret dialog are the same string. If you mistype
one character, every fire returns bad_otp.
Setting up the credential — receiver side
On the receiving station (the one whose action you want to fire):
- Open Actions in the sidebar.
- In the OTP Credentials table, click + New Credential.
-
Name the credential after the operator who will be allowed to
fire it (e.g.
NW5W) and submit. - The reveal panel appears. Copy the Secret Key from the right side — the long base32 string, not the QR code. The page warns that this is the only time the value is shown.
-
Bind the credential to the Action whose name the sender will
type — e.g.
unlock— via that Action’s OTP credential field with Require OTP on.
Send the Secret Key to the sender over a trusted channel.
Setting up the credential — sender side
On the sending station (the one this page is on):
- Open Messages in the sidebar.
- Open a DM thread to the receiving callsign. (Tactical, multi-recipient threads do not show the zap icon — an OTP-protected fire to many callsigns at once would be an operational footgun.)
- Click the zap icon (⚡) in the thread header to open the Remote Actions drawer. The drawer anchors right on desktop and slides up from the bottom on mobile.
- Click Manage One-Time Passwords... (under the OTP picker, or via the top-level Messages overflow menu).
-
Click + New Secret. Give it a name that
identifies the remote station — e.g.
NW5W OTP. - Paste the Secret Key you copied from the receiver into the Secret Key field. Whitespace is tolerated; case does not matter.
- Save.
The new secret now appears in the OTP picker on every macro you create against any thread.
Creating macros
A macro is a saved tile that fires a specific
action against a specific remote station with a specific argument
list. Macros are scoped per thread — the macros you create
while the drawer is open against NW5W-9 only show
up on threads to NW5W-9.
- Open the drawer on the target thread.
- Click Edit macros at the bottom of the drawer.
-
Click + Add new macro. Fill in:
- Label — what the tile says (e.g.
unlock front). - Action — the action name as defined on the receiver (e.g.
unlock). - Args — space-separated
k=vpairs, or empty. - OTP Secret — pick the credential you saved above, or leave blank for manual OTP (you’ll be prompted to type a code at fire time, useful for actions on receivers where the operator types the code from a phone authenticator).
- Label — what the tile says (e.g.
- Save. The tile appears in fire mode and is reorderable by drag.
Deleting a credential demotes its bound macros to manual-OTP rather than deleting them, so you can rotate a Secret Key without losing the macro layout.
Firing
Two ways to send a Remote Action:
-
Tap a tile. The frontend asks the backend for
a fresh six-digit OTP from the bound credential, assembles
@@<digits>#<action> [args], and posts it through the same send path as a hand-typed line in the thread. The outbound bubble looks identical to a normal message because it is a normal message — only the body differs. - Free-form sender. The drawer’s text field at the bottom lets you type an action name + args without saving a macro. Pick an OTP secret (or manual OTP), type the line, send.
The SEND button greys out when the assembled wire string would exceed the APRS frame budget (67 characters by default; 200 if you have Allow long APRS messages enabled in Preferences). Shorten args to enable the button.
A short cooldown countdown sits on each tile right after a fire — the receiver’s replay ring will reject the same OTP twice in the same 30-second TOTP step, and the cooldown is the UI’s polite reminder of that.
Reading replies
Inbound text from the same callsign within 60 seconds of an outbound fire that begins with one of these status keywords gets a zap-tagged badge in the bubble footer:
ok · error: ·
bad_otp · bad_arg ·
denied · unknown ·
disabled · busy ·
rate_limited · timeout
· no_credential
Inbound text within the same 60-second window that does
not begin with a status keyword stays a normal chat
bubble. The trade-off is intentional: a free-form remark from
the peer that happens to start with ok will be
mis-badged, but unrelated chat will not be. False negatives are
preferred over false positives.
Troubleshooting
-
bad_otpreply. The two stations’ clocks differ by more than one TOTP step (30 s). Sync NTP on both. If you just rotated the Secret Key on the receiver, update the matching secret in the sender’s credentials modal — one mistyped character produces this every time. -
denied. The receiver’s Action has a sender allowlist that excludes your callsign. The operator on the receiver side has to add you. -
unknown. The action name is misspelled, the Action has been deleted on the receiver, or the Action is disabled. Check the macro label vs. the Action name on the receiver. -
bad_otpon rapid re-fire. The receiver rejects the same OTP twice within its 30-second window (replay protection). Wait for the tile’s cooldown countdown to clear and try again. Distinguishable from a mistyped Secret Key in that it only happens on the second of two fast clicks; a mistyped key fails every time. - SEND disabled with a tooltip. The assembled line exceeds the APRS frame budget. Shorten args or enable Allow long APRS messages on the Preferences page (200-char frames, only safe when both stations support it).
- No zap icon on a thread. Tactical (multi- recipient) threads omit the icon by design. Open or create a DM to that callsign instead.
- Reply has no zap badge. Either the inbound arrived more than 60 s after the fire, or its first word is not in the status-prefix allowlist. Both are normal.