Examples
End-to-end recipes for the most common CLI workflows. Every example assumes you've installed the CLI (Install) and configured a key (Auth and Keys). Outputs are abbreviated for readability.
1. Log a one-off POTA contact
You've already got an activation folder created -- maybe from the web app, maybe from hamtrax activations create. Now you want to log a single QSO into it.
# Find the folder id
hamtrax activations list --in-progress --json | jq '.items[0]'
# {
# "id": "fld_8a4f0c2b9e1d",
# "name": "N0CALL@K-1234-20260507",
# "locationReference": "K-1234"
# }
# Log the contact -- mySig=POTA, mySigInfo=K-1234 are auto-populated server-side
hamtrax contacts create \
--folder fld_8a4f0c2b9e1d \
--callsign W1AW \
--frequency 14.074 \
--mode FT8
# QSO logged (id: qso_92b1f4d2e8a0)
The QSO appears in the web app immediately and counts toward your nativeQsoCount. Free-tier users can log up to 200 native QSOs (web + CLI combined); see Troubleshooting if you hit the cap.
2. Run a full activation end-to-end
This is the everyday Pi-in-the-field flow -- one script that creates the activation folder, then logs a stream of contacts as you work them.
#!/usr/bin/env bash
set -euo pipefail
REFERENCE=K-1234
MY_CALL=N0CALL
# 1. Create (or reuse) the activation folder. This is idempotent --
# running it twice in a row gives you the same folder id.
FOLDER_ID=$(hamtrax activations create \
--reference "$REFERENCE" \
--callsign "$MY_CALL" \
--json | jq -r '.id')
echo "Activation $REFERENCE ready: $FOLDER_ID"
# 2. Log contacts as you work them. mySig=POTA, mySigInfo=K-1234
# are auto-populated by the server because $FOLDER_ID is an
# activation folder.
log_qso() {
hamtrax contacts create \
--folder "$FOLDER_ID" \
--callsign "$1" \
--frequency "$2" \
--mode "$3" \
--json \
| jq -r '.id'
}
log_qso W1AW 14.074 FT8
log_qso K5ZD 14.250 SSB
log_qso JA1ABC 21.030 CW
Idempotent activation create means a second logger script (or AI agent, or web-app entry) won't double-create the folder -- the server uses a Firestore transaction keyed on (callsign, locationReference, startDate).
3. List and export an activation's contacts
After the activation, pull the QSO list and pipe it through jq for a quick summary.
FOLDER_ID=fld_8a4f0c2b9e1d
# Stream every QSO as NDJSON, one per line
hamtrax contacts list --folder $FOLDER_ID --ndjson \
| jq -s 'group_by(.mode) | map({mode: .[0].mode, count: length})'
# [
# { "mode": "FT8", "count": 42 },
# { "mode": "CW", "count": 18 },
# { "mode": "SSB", "count": 11 }
# ]
For ADIF/CSV export, use the web app's exporter -- the CLI's contact-list endpoint emits raw JSON, not ADIF, by design.
4. Switch between basic and elevated keys
You normally use a basic key (read + create) so the CLI can never accidentally delete a QSO. When you need to clean something up, you swap in an elevated key for the duration of the cleanup, then put the basic key back.
# Normal logging — basic key in keychain
hamtrax whoami
# tier: basic
# A bad QSO snuck in. Switch to elevated for one command.
HAMTRAX_API_KEY=htx_live_<elevated-key> hamtrax contacts delete qso_92b1f4d2e8a0 --yes
# Deleted qso_92b1f4d2e8a0
# Keychain still holds the basic key -- next call uses it
hamtrax whoami
# tier: basic
The env-var override is the cleanest way to scope an elevated action to a single command. See Auth and Keys → Resolution order.
5. Keep a long-running portable session healthy
When you're activating from a remote site for hours, the dev-quality-of-life moves are:
# Stash the in-progress activation id in a variable so every later
# command is a one-liner.
ACTIVATION=$(hamtrax activations list --in-progress --limit 1 --json | jq -r '.items[0].id')
# Helper alias for the rest of the session
log() {
hamtrax contacts create --folder "$ACTIVATION" --callsign "$1" --frequency "$2" --mode "$3"
}
log W1AW 14.074 FT8
log K5ZD 14.250 SSB
If your shell exits, restart, re-export ACTIVATION, and keep going. The folder is durable; only the local variable is lost.
6. Provision a fresh machine non-interactively
For a CI runner, a freshly imaged Pi, or a Docker container, skip the interactive auth login and pipe a pre-generated key.
# Pi setup script — runs once at first boot
echo "$HAMTRAX_PROVISION_KEY" | hamtrax auth set-key
hamtrax whoami --json > /tmp/whoami.json || {
echo "key invalid or revoked"; exit 3;
}
Or skip storage entirely and just run with the env var set:
docker run -e HAMTRAX_API_KEY=htx_live_xxx -e HAMTRAX_NO_KEYRING=1 \
node:20-alpine sh -c 'npm i -g hamtrax && hamtrax whoami --json'
See Install → Docker / CI for more.
7. Drive the CLI from an AI agent
The CLI is designed to be operated by an LLM. Give it the help corpus and a key, and it constructs valid commands without any other context.
# 1. Capture the help corpus
hamtrax help --all > /tmp/hamtrax-help.txt
# 2. Set up an env var for the agent to use
export HAMTRAX_API_KEY=htx_live_xxxxxxxxxxxxxxxxxxxxxxxx
# 3. The agent now runs commands like:
hamtrax activations create --reference K-1234 --callsign N0CALL --json
hamtrax contacts create --folder fld_... --callsign W1AW --frequency 14.074 --mode FT8 --json
For the full agent guide -- env-var auth, structured output, exit-code handling, sample LLM prompts -- see AI Agent Guide.
Related pages
- Command Reference -- every flag
- AI Agent Guide -- automation patterns
- Auth and Keys -- tiers, env-var override
- Troubleshooting