Guides menu
Start
All guidesGuides
Uptime Kuma alerts on your iPhoneApprove a GitHub deploy from your iPhoneHome Assistant alerts on your iPhone and Apple WatchForms on your site
Add your Nowlark form to WordPressAdd your Nowlark form to WordPress.comAdd your Nowlark form to WixAdd your Nowlark form to WebflowAdd your Nowlark form to GhostAdd your Nowlark form to Google SitesAdd your Nowlark form to a site you build yourselfReference
API referenceSupportApprove a GitHub deploy from your iPhone
Your workflow pauses before production and asks on your iPhone. Approve and it deploys; deny or ignore it and nothing ships.
What you need#
- Nowlark on your iPhone, and your key from Settings › Connect an App › Create Your Key. Copy it when it is shown, because it is shown once. It starts
nlk_. - A GitHub repository that uses GitHub Actions. The question is one job with
curlandjq, no marketplace action.
1. Store your key as a secret#
In the repository, open Settings, then Secrets and variables › Actions, and click New repository secret. Set Name to NOWLARK_API_KEY, paste your key into Secret, and click Add secret.
2. Add the approval job#
Save this as .github/workflows/deploy.yml, put your own deploy steps in the deploy job, and commit it to your default branch:
name: Deploy
on:
workflow_dispatch:
jobs:
approve:
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- name: Ask on my iPhone
env:
NOWLARK_API_KEY: ${{ secrets.NOWLARK_API_KEY }}
run: |
body=$(jq -n --arg repo "${{ github.repository }}" \
--arg sha "${{ github.sha }}" --arg who "${{ github.actor }}" \
'{source:"Deploy", title:"Deploy \($repo) to production?",
body:"\($sha[0:7]) by \($who)", priority:1,
replies:"approve_deny", reply_within:1800}')
id=$(curl -sf https://nowlark.com/v1/notify \
-H "Authorization: Bearer $NOWLARK_API_KEY" \
-H "Content-Type: application/json" -d "$body" | jq -r .id)
while true; do
r=$(curl -sf "https://nowlark.com/v1/receipts/$id" \
-H "Authorization: Bearer $NOWLARK_API_KEY") || { sleep 10; continue; }
case $(jq -r .reply_state <<<"$r") in
answered) [ "$(jq -r .reply <<<"$r")" = approve ] && exit 0
echo "Denied on the phone"; exit 1 ;;
expired) echo "Nobody answered in 30 minutes"; exit 1 ;;
esac
sleep 10
done
deploy:
needs: approve
runs-on: ubuntu-latest
steps:
- run: echo "Deploying" # your deploy steps go here
The approve job sends the question and then checks every 10 seconds for your answer, trying again if a check does not get through. The deploy job only starts when the answer is Approve.
3. Run it#
Open the Actions tab, choose Deploy, and click Run workflow. Within seconds your iPhone shows the question. Press and hold it to see Approve and Deny.
| You | The workflow |
|---|---|
Tap Approve |
The approve job succeeds and the deploy job runs. |
Tap Deny |
The run fails with "Denied on the phone". Nothing is deployed. |
Do nothing for 30 minutes |
The run fails with "Nobody answered in 30 minutes". Nothing is deployed. |
The first answer counts, so a second tap from another device cannot change it.
Good to know#
- While it waits, the approve job is a running job, so a question left unanswered for the full 30 minutes uses 30 minutes of Actions time. Shorten it by lowering
reply_within(in seconds) andtimeout-minutestogether. - Replies covers the other answer sets (Yes and No, and a Later button) and how a server can get the answer as a signed callback instead of asking for it.