You are helping me connect my code to Nowlark, a service that sends push notifications to my iPhone from a script, cron job, server or app. One HTTPS request with an API key and the notification is on my phone. There is no SDK to install and nothing to sign in to. Your job is to get a working, tested integration into my project, asking me only what you cannot find out yourself. REFERENCE (read it if anything below is unclear): https://nowlark.com/api HOW NOWLARK WORKS - Endpoint: POST https://nowlark.com/v1/notify - Auth: header X-Nowlark-Key: nlk_... (or Authorization: Bearer nlk_...). The API key starts with nlk_ and can only send. A key starting with nla_ is an account key: it is the wrong one, tell me to use an nlk_ key instead. - Body (JSON): source (required, the sender's name), title and/or body (at least one), url (optional, http or https only), priority (optional, -2 to 2, default 0), dedupe_key, group_key, replace_key (optional strings), delay (optional, seconds, 10 to 604800, to deliver later), callback_url (optional https URL called once when I read it), ttl (optional seconds before Apple drops an undelivered push), tags (optional, up to 5 short labels). - Priority: -2 and -1 are silent (no sound, and still kept in the app's feed), 0 is normal, 1 breaks through Focus, 2 breaks through Focus and repeats until I open it. Use 1 or 2 only for things that need me now. - Success is HTTP 200. "duplicate": true means the dedupe_key was already used and nothing was pushed: that is not an error, never retry or alert on it. "delivered": 0 with "devices": 0 means no phone has registered yet, not a failure. "muted": true means I muted that source in the app: it is kept in the app's history but not pushed. The response also carries "id", "remaining" (calls left this hour) and "reset_at". - Errors are JSON with "error" and "message": 400 invalid_request (missing source, or no title and no body), 401 auth_required / invalid_key / wrong_credential, 402 upgrade_required (images and buttons need the Upgrade Pass, so leave them out), 429 rate_limited (1000 an hour per key). - GET https://nowlark.com/v1/key/check with the same header proves a key works without sending anything and without using up the hourly limit. - Optional ready-made senders, only if they fit my project: https://nowlark.com/clients/nowlark.py (Python) and https://nowlark.com/clients/nowlark (shell). Plain HTTP from my own code is just as good. FIRST, LOOK AT MY PROJECT, THEN ASK ME Inspect the repository or machine before asking anything, and skip any question the code already answers. Then ask me, all at once and briefly, whatever is still open: 1. What should notify me? (a job finishing, an error, a deploy, a threshold, a new item) And when should it stay quiet? 2. Which events deserve priority 1 or 2, and which should be silent? 3. Where does this run (cron, launchd, a server, CI, a container, a serverless function), so you can pick where the key lives? 4. Do I already have a Nowlark API key? If not, tell me: open the Nowlark app, Settings, Connect an App, Create Your Key. It is shown once. The same screen has the address and the key ready to copy. HANDLING MY KEY - The key is a secret. Read it from the environment variable NOWLARK_API_KEY (or this project's existing secret store). Never write it into source code, a committed file, a log line or a URL. - Cron runs with an almost empty environment and reads no shell profile, and launchd does not inherit it either. For either, set NOWLARK_API_KEY on the crontab line or in the launchd plist's environment, or have the script read it from a permission-restricted file. Do not assume it is exported. - If it has to be stored, put it in an untracked file, a crontab or launchd environment entry, or the platform's secret manager, and add the file to .gitignore. - Do not ask me to paste the key into this chat unless there is no other way to hand it to the machine that runs the code. If I do paste it, use it only for the test below and never repeat it back. - One key per script or service is better than one shared key, because one runaway loop cannot silence the others (the Upgrade Pass allows several keys, a free account has one). NAMING THE SENDER The source is the name my phone shows and the row it is filed under, where I can mute or colour it. - One name per job, the same on every run: "Nightly backup", "CI", "Certificate renewal". - Never a machine name shared by several jobs, and never a changing detail such as a date, a count or a hostname. Put those in the title or body. - A job that only speaks on failure should register its name first: POST https://nowlark.com/v1/sources with {"source": "Nightly backup"}. It is free and safe to repeat. BUILD IT - Add a small send function or script in the project's own language and style. Set a timeout of about 20 seconds. Give it a way to send a one-off test (a flag, a command or a test) so you can run the proof below through your own code. - A failed notification must never break or hang the job it reports on: catch errors, log them to stderr, carry on. - If a job can fire the same alert repeatedly (a retry, a loop, a cron that re-checks), send a stable dedupe_key so I am woken once (later sends with the same key are dropped). Use replace_key for a status that updates in place: a later send from the same source with the same replace_key removes the earlier notification and takes its place. - Keep titles short and put the detail in the body. If there is a page worth opening, pass it as url. - Do not retry a 400, 401 or 402: fix the request. Retry a network error or 5xx at most twice, with a short pause. On 429 do not retry: log it and give up on that send (a long-running process should pause until the hour resets). PROVE IT WORKS BEFORE YOU SAY IT DOES Do these through the code you wrote, not by hand-written curl, so each real notification you send is one I expect (the test below is the only success-path send I want). 1. Call GET https://nowlark.com/v1/key/check and show me the status code and the label it returns, not the key. 2. Send one real test notification through the code you wrote, with title "Nowlark is connected" and the project's source name. Show me the response. Tell me to confirm it arrived on my phone. 3. Run the failure path on purpose, once with a bad key against the real endpoint (expect 401 invalid_key) and once with an unreachable address (expect your retries, then a log line), and confirm the job still finishes normally and the failure is logged. WHEN YOU FINISH, REPORT The files you changed, where the key is read from, the source name or names you chose, which events send at which priority, how your code handles each of: a network error, a 5xx, 400, 401, 402 and 429 (one line each, matching the rules above), what you tested and what you could not (for example, whether the phone actually showed it), and the one thing I should do next if anything is left.