9 July 2026

Push notifications from any script — the appliance as an alert channel

Send informational push notifications to enrolled phones with one curl call: server alerts, on-call pings, price watchers, home automation.

The Notakey appliance is usually described as an authentication server: a login happens, a push request lands on the phone, the user approves. But the same delivery channel accepts a second message type, a plain notification, and that turns the appliance into something more general: a push-messaging channel to every phone enrolled in your service, callable from any script with a single curl.

any script ──HTTPS──▶ appliance API ──push──▶ enrolled phone
 (cron, monitoring,    /notify                 Notakey Authenticator
  home automation…)

Unlike an authentication request, a notification doesn’t ask for approval: it just appears on the phone, addressed to a username, and is delivered to all of the user’s enrolled devices at once. That makes it a drop-in replacement for the places you’d otherwise wire up SMS (per-message cost, spoofable sender) or email (ignored until Monday): job monitoring, on-call pings, employee announcements.

Requirements

  • A running Notakey appliance (cloud or on-premise) with a service and at least one user with an onboarded phone. If you already run VPN 2FA or SSO, you have all of this: notifications go through the same service your logins use, or a separate one if you want different branding.
  • API access credentials (a client ID and a client secret), created in the dashboard under Access credentials (Step 1 below).
  • curl and jq on anything that can reach the appliance. That’s the whole dependency list.

Step 1 — Create API access credentials

In the dashboard, open Access credentials and create a credential for your scripts. Two things matter here:

  • Scopes. Grant urn:notakey:notify. That is the scope this guide needs. urn:notakey:auth exists too, for creating authentication (approve/deny) requests; add it only if the same credential will do both. A notify-only credential can’t be abused to trigger login approvals, so keep the scope list as short as the job allows.
  • You receive a client ID and a client secret. The secret authorizes messaging everyone in the service, so treat it like a root password.

Step 2 — Exchange it for a token, and keep the token fresh

The notify call itself doesn’t use the client secret. It uses a bearer access token obtained through the standard OAuth 2.0 client-credentials grant. Access tokens are deliberately short-lived: plan to renew about once an hour, or your scripts will start failing with authorization errors at some point after they’ve been running fine for 59 minutes.

So token renewal is a cron job, not a setup step:

#!/bin/bash
# /usr/local/bin/ntk-token-renew — cron: 0 * * * *

curl -s -X POST https://ntk.example.com/api/token \
  -d 'grant_type=client_credentials&client_id=<client-id>&client_secret=<client-secret>&scope=urn:notakey:notify' \
  | jq -r .access_token > /etc/notakey/api.token

The script embeds the client secret and writes the token, so lock both down:

chmod 700 /usr/local/bin/ntk-token-renew    # root-only, holds the secret
install -m 600 /dev/null /etc/notakey/api.token

If you also granted urn:notakey:auth, request it as a separate token into a separate file (same call, scope=urn:notakey:auth) rather than one token with both scopes; the notification scripts then never hold a token that could create login approvals.

Step 3 — One reusable notify script

Everything else in this guide calls this one script. It takes a username, a title and a message body:

#!/bin/bash
# /usr/local/bin/ntk-notify <username> <title> <description>

token=$(cat /etc/notakey/api.token)

curl -X POST -H "Content-Type: application/json" \
  -H "Authorization: Bearer $token" \
  -d '{ "username": "'"$1"'", "title": "'"$2"'", "description": "'"$3"'", "type": "notification" }' \
  "https://ntk.example.com/api/v3/services/<service-id>/notify"

Replace ntk.example.com with your appliance address and <service-id> with the service UUID from the dashboard. Test it:

ntk-notify j.doe "Test" "If you can read this on your phone, the channel works."

The push arrives in the Notakey Authenticator app, the same app the user already has for logins, so there is nothing new to install, explain, or get past mobile-device management.

Step 4 — Call it from anything

Once the channel is a one-liner, it collects use cases. Some that run in production today:

A backup job that reports back. The classic silent failure: backups that stopped working months ago and nobody noticed. Two lines at the end of the job fix that:

if ! /usr/local/bin/backup-run; then
  ntk-notify admin "Backup FAILED" "Nightly backup on $(hostname) exited with an error — check /var/log/backup.log"
fi

Disk space, certificate expiry, anything cron can check:

#!/bin/bash
# cron: 0 8 * * *
used=$(df --output=pcent / | tail -1 | tr -dc '0-9')
if [ "$used" -gt 90 ]; then
  ntk-notify admin "Disk warning" "Root filesystem on $(hostname) is at ${used}% — time to clean up."
fi

An announcement to every employee. The API addresses one username per call, so a company-wide message is a loop over your user list (maintenance windows, office closures, incident notices):

while read -r user; do
  ntk-notify "$user" "IT maintenance" "VPN unavailable Saturday 06:00–08:00 — planned appliance upgrade."
done < users.txt

Electricity spot prices, twice every two hours. Not everything worth pushing is an outage. This one runs from cron and tells the user what the next hour of electricity will cost, handy for deciding when to run the dishwasher:

#!/bin/bash
# cron: 5 * * * * — sends on even hours, 06–23 only
hour=$(( $(date +%H) + 1 ))
next=$(( hour + 1 ))

if [ "$hour" -gt 5 ] && [ "$hour" -lt 24 ] && (( $(date +%H) % 2 == 0 )); then
  ntk-notify "$1" "Electricity" \
    "Next hour: $(spot_price "$hour")€/kWh. After that: $(spot_price "$next")€/kWh."
fi

(spot_price is whatever fetches your market data: an exchange API, a cached CSV. The point is the delivery, not the source.)

Two documented extras worth knowing for recurring messages like this one: adding a fingerprint field to the payload makes a repeat send with the same fingerprint update the existing message instead of stacking a new one, so a price ticker stays one notification, not forty a day. And "type": "sms" sends the same message as an SMS instead, if the user has a mobile number defined: a fallback channel for someone whose phone lost the app.

The washing machine is done. A smart plug watching power draw, a Home Assistant automation, a script polling a meter — whatever detects the end of the cycle, the notification is the same one-liner. Silly example, real habit: once sending a push costs nothing, you notify about everything.

What this channel is (and is not) good for

Compared to SMS, the recipient side is much stronger: an SMS arrives on whatever handset currently holds the SIM, from a sender name anyone can fake, while a Notakey notification lands only in the Authenticator app on devices that completed cryptographic enrollment in your service. Nobody can subscribe themselves to your alerts, and nobody can spoof the sender.

One honest limitation, straight from the API documentation: the notification body itself is not end-to-end encrypted: like any mobile push, it is relayed through Apple’s and Google’s push services and is readable by apps with notification access on the device. So treat the message body like a pager message, not like a sealed envelope: “Backup failed on host X” is fine; a password or an API key is not. When you need to deliver something genuinely secret, use an authentication request (urn:notakey:auth) instead. There the push is only a knock on the door, and the payload is fetched by the app over its certificate-authenticated channel after the user responds.

Where this fits

If the appliance already protects your VPN or applications, notifications are free capability you’re not using: same service, same app, same API credentials, one extra endpoint. And if you’ve been paying an SMS gateway for internal alerts, this replaces it for every recipient who carries an enrolled phone.

← All posts

See your first passwordless login this week

A 30-minute call with an engineer, not a sales deck. We’ll map your VPN, SSO or Windows setup to a working pilot.