push notifications via webhook
$ curl -X POST https://bzap-server.fly.dev/v1/your_secret \ -d '{"title":"Deploy","message":"v2.1 is live! 🚀"}' {"message":"Notification sent"}
Bzap fits into your workflow, whatever that looks like.
Motion alerts, leak detection, temperature drops. Tap a button on the notification to turn on lights or lock doors.
Know the moment your build passes, deploy finishes, or tests fail. Approve deploys from the notification.
Using Claude Code or Copilot? Get notified when tasks finish. Review and approve from your phone.
Uptime checks, error spikes, disk warnings. Restart services or scale up with one tap.
Long-running backups, data exports, ML training. Get pinged when done — or when they crash.
If it can make an HTTP request, it can send you a Bzap. Python, Node, Go, Bash, Zapier, n8n.
Action buttons that fire webhooks back. Your phone becomes a remote control.
Other push apps are one-way. Bzap lets you respond.
{
"title": "Motion Detected",
"message": "Front porch camera",
"actions": [
{
"id": "lights",
"label": "Turn On Lights",
"webhook": "http://ha.local/api/lights"
}
]
}
Bzap is opinionated about simplicity.
Action buttons fire webhooks back
Share webhook as scannable QR
3 Shortcuts intents
GitHub, Docker, Python...
Full-text + JSON/CSV export
Messages never stored on server
iPhone & iPad native
Target specific devices
Simple REST API. JSON in, push notification out.
| Field | Type | Description |
|---|---|---|
title | string | Notification title |
subtitle | string | Subtitle line |
message | string | Body text |
thread_id | string | Group by thread |
sound | string | Notification sound |
open_url | string | URL to open when tapped |
image_url | string | Image attachment |
interruption_level | string | passive / active / time-sensitive |
actions | array | Action buttons with response webhooks (max 4) |
Add up to 4 action buttons. Each button fires a webhook when tapped.
$ curl -X POST https://bzap-server.fly.dev/v1/your_secret \ -H 'Content-Type: application/json' \ -d '{ "title": "Deploy Ready", "message": "v2.3.1 — all tests passing", "actions": [ { "id": "deploy", "label": "Deploy to Prod", "webhook": "https://your-ci.com/deploy" }, { "id": "rollback", "label": "Rollback", "webhook": "https://your-ci.com/rollback" } ] }' {"message":"Notification sent"}
Two-way communication. Send a notification, get an answer back. Add response_channel: true to any action to enable polling for the user's response.
Ask a yes/no question. The response includes which button was tapped.
# Step 1: Send notification with response_channel actions $ curl -s -X POST https://bzap-server.fly.dev/v1/your_secret \ -H 'Content-Type: application/json' \ -d '{ "title": "Deploy to Production?", "message": "v2.3.1 — all tests passing", "actions": [ {"id": "approve", "label": "Approve", "response_channel": true}, {"id": "reject", "label": "Reject", "destructive": true, "response_channel": true} ] }' {"message":"Notification sent","response_id":"abc-123"} # Step 2: Poll for the user's response (Bearer auth) $ curl -s https://bzap-server.fly.dev/v1/responses/abc-123 \ -H 'Authorization: Bearer your_secret' # While waiting: HTTP 202 {"status":"pending"} # After user taps a button: HTTP 200 {"status":"responded","action_id":"approve","device_name":"iPhone"}
Up to 4 custom buttons. Each has its own id returned in the response.
$ curl -s -X POST https://bzap-server.fly.dev/v1/your_secret \ -H 'Content-Type: application/json' \ -d '{ "title": "Which environment?", "message": "Ready to deploy feature-login", "actions": [ {"id": "staging", "label": "Staging", "response_channel": true}, {"id": "production", "label": "Production", "response_channel": true}, {"id": "cancel", "label": "Cancel", "destructive": true, "response_channel": true} ] }' {"message":"Notification sent","response_id":"def-456"} # Poll → user taps "Production" {"status":"responded","action_id":"production","device_name":"iPad"}
Ask the user to type a response. Set type: "text_input" to show a text field when the button is tapped.
$ curl -s -X POST https://bzap-server.fly.dev/v1/your_secret \ -H 'Content-Type: application/json' \ -d '{ "title": "What branch?", "message": "Which branch should I deploy?", "actions": [ { "id": "reply", "label": "Reply", "type": "text_input", "text_input_placeholder": "Branch name...", "response_channel": true } ] }' {"message":"Notification sent","response_id":"ghi-789"} # Poll → user types "feature/login-v2" {"status":"responded","action_id":"reply","text":"feature/login-v2","device_name":"iPhone"}
1. Send a notification with response_channel: true on one or more actions.
2. The server returns a response_id — your ticket to poll for the answer.
3. Poll GET /v1/responses/{response_id} with Bearer auth.
→ 202 while waiting
→ 200 with the response (one-time read, then deleted)
→ 404 if expired (5 min TTL)
4. Responses are one-time-read — after you get a 200, the row is deleted.
5. Actions can have both webhook and response_channel — the webhook fires immediately, and you can still poll.
| Field | Type | Description |
|---|---|---|
id | string | Unique action identifier (returned in response) |
label | string | Button label shown to user |
webhook | string | URL to POST when tapped (optional) |
destructive | bool | Show button in red (optional) |
response_channel | bool | Enable polling for this action's response |
type | string | "text_input" to show a text field |
text_input_placeholder | string | Placeholder text for text input |
Your service pings Bzap. If it stops, you get alerted.
1. Create a Heartbeat monitor in the app — you get a unique ping URL.
2. Add a curl call to the end of your script, cron job, or pipeline.
3. If the ping stops arriving within the expected interval + grace period, Bzap sends you a push notification.
4. Respond from your lock screen — tap Restart, Acknowledge, or fire a webhook.
Add a ping at the end of your cron script. If the job fails or hangs, no ping is sent and you get alerted.
#!/bin/bash # Daily database backup pg_dump mydb > /backups/$(date +%F).sql # Tell Bzap we're alive curl -s -X POST https://bzap-server.fly.dev/v1/heartbeat/your_token
Ping after a successful deploy. If the pipeline breaks silently, you know.
- name: Deploy run: flyctl deploy --remote-only - name: Heartbeat run: curl -s https://bzap-server.fly.dev/v1/heartbeat/your_token
Ping after processing each batch. If the worker crashes or gets stuck, silence triggers the alert.
while True: batch = queue.get_batch() process(batch) # Heartbeat after each batch requests.post("https://bzap-server.fly.dev/v1/heartbeat/your_token")
A sensor or edge device pings every few minutes. Goes silent = offline.
# Read sensor + ping Bzap TEMP=$(cat /sys/class/thermal/thermal_zone0/temp) curl -s -X POST https://bzap-server.fly.dev/v1/heartbeat/your_token
An autonomous agent pings after each task. If it crashes or gets stuck, you get alerted on your phone.
while true; do claude --task "$NEXT_TASK" curl -s https://bzap-server.fly.dev/v1/heartbeat/your_token done
| Setting | Description | Default |
|---|---|---|
interval | How often you expect a ping (1, 5, or 15 min) | 5 min |
grace_period | Extra wait time after interval before alerting | Same as interval |
failure_threshold | Consecutive misses before marking as down (1-10) | 3 |
For HTTP monitors, you can also check the response body for a keyword. Set the method to GET and provide a keyword — Bzap will alert if the keyword is missing (or present, if you choose "must NOT contain").
# Create a monitor that checks for "healthy" in the response $ curl -s -X POST https://bzap-server.fly.dev/v1/monitors \ -H 'Authorization: Bearer your_secret' \ -H 'Content-Type: application/json' \ -d '{ "name": "API Health", "url": "https://api.example.com/health", "interval": 60, "method": "GET", "keyword": "healthy", "keyword_should_exist": true }'
iPhone + iPad. Same account, same notifications.
The most reliable way to set up a second device is the QR code flow. It works instantly, across any Apple ID, with no waiting:
On your existing device (the one that already has your account):
Settings → Link Device → Show QR Code
On your new device:
Settings → Link Device → Scan QR Code
The new device imports your account secret and registers itself with the server. Both devices will receive notifications from all your webhooks.
Bzap also syncs your account secret via iCloud Keychain in the background. If both devices share the same Apple ID with Passwords & Keychain enabled, the secret will eventually sync automatically.
However, this sync is not instant — it can take seconds to minutes depending on network conditions. If the new device launches before the sync completes, it will generate a new (separate) account. That's why QR linking is the recommended approach for the initial setup.
Once both devices share the same secret (via QR or sync), future changes like secret rotation will sync automatically via iCloud Keychain.
Bzap uses a secret as your account identifier — no email, no password. Every device with the same secret is part of the same account. When a notification is sent to your webhook, the server pushes it to all registered devices.
Subscriptions are tied to your Apple ID via StoreKit, so they work across all your devices automatically — no extra steps needed.
| Issue | Solution |
|---|---|
| New device doesn't see my monitors | Use Link Device → Scan QR from your existing device. This is the fastest and most reliable method. |
| iCloud sync didn't work | iCloud Keychain sync can be slow. Don't wait — use the QR code flow instead. Check Settings → Apple ID → iCloud → Passwords & Keychain is on for future syncs. |
| Different Apple IDs on devices | QR code flow works across any Apple ID — no iCloud needed |
| Subscription not showing on second device | Tap Restore Subscription on the Subscription page |
| Notifications only on one device | Make sure push notifications are enabled in system settings on both devices |
Free to try. One webhook. Infinite possibilities.
⚡ Get Bzap