Skip to main content

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.