Webhook Universal
Arahkan webhook JSON dari layanan apa pun ke relay dan dapatkan notifikasi di iPhone Anda. Layanan yang dikenali PushWard mendapatkan preset, dengan Aktivitas Langsung untuk peringatan.
The universal webhook runs on the hosted Relay, so there is nothing to deploy. It is for services the relay has no route for. Grafana, ArgoCD, the *arr apps and the other supported providers get purpose-built Live Activities on their own routes, and the relay recognises most of them on this URL too.
Get Your Integration Key
Gunakan integration key default Anda dari aplikasi PushWard di Settings → Integration Key, atau buat scoped key untuk integrasi ini.
Send a webhook
Set the service's webhook URL to the relay root, https://relay.pushward.app/, and send your key as a Bearer token. The body can be any JSON object or array up to 1 MB. There is nothing to set up or confirm: the first event arrives like every other.
curl -X POST "https://relay.pushward.app/?source=backup" \
-H "Authorization: Bearer hlk_..." \
-H "Content-Type: application/json" \
-d '{"job":"nightly-offsite","status":"finished","message":"Uploaded 1000 chunks in 42 minutes"}'Plenty of services can only set a URL. Put the key in it as the Basic Auth password; the username is ignored:
https://pushward:[email protected]/?source=backupName the sender
?source= is optional, but set it. Each source's notifications get their own thread, a payload with no title of its own is titled after it, and it is the subtitle on cards. A few presets only apply when the source names their service (see the table below). It takes lowercase letters, digits and dashes, up to 32 characters; anything else is a 422.
Services the relay already knows
Before anything else, the relay checks whether the payload comes from one of its providers. A recognised payload is handled exactly as if it had been posted to that provider's route: same Live Activity, same query parameters, same response.
| Recognised by | Services |
|---|---|
The User-Agent header | Radarr, Sonarr, Prowlarr |
An X-Gitea-Event or X-Forgejo-Event header | Gitea and Forgejo Actions runs |
| Fields in the JSON body | Grafana, ArgoCD, Backrest, Changedetection.io, Gatus, Jellyfin, Komodo, Overseerr / Jellyseerr, Paperless-ngx, Proxmox VE, Uptime Kuma, and Bazarr and Unmanic through Apprise |
Detection is deliberately conservative, so when a service lets you set the path, use its own route anyway. Payloads from GitHub, GitLab, Bitbucket and Sentry (recognised by their event headers), and from Lidarr, Readarr and Whisparr (by their User-Agent), go to the universal webhook with the service's name as their source, unless you set one.
Two providers need their own route. TrueNAS is never detected, because the OpsGenie protocol it speaks is not TrueNAS's alone: keep its API URL at https://relay.pushward.app/truenas. Gitea and Forgejo events other than Actions runs are not detected either, and arrive as notifications.
Presets
For services whose webhook format is documented, the relay ships a preset: which field is the title, the body, the link, what keys one alert, and what each status and severity value means. A preset is picked by the fields a payload has, never by guessing from its values, so every event of a kind arrives the same way. Alert-style services open an alert Live Activity that updates as the alert changes and resolves in green when it clears. CI runs and deploys open a progress card that finishes as "Done", or in red when the run failed.
| Service | Events | Arrives as |
|---|---|---|
| Prometheus Alertmanager | Alert groups | Alert card |
| PagerDuty | Incidents (v3 webhooks) | Alert card |
| Opsgenie | Alert actions | Alert card |
| Grafana OnCall | Alert groups (outgoing webhook) | Alert card |
| Atlassian Statuspage | Incidents and component changes | Alert card |
| Azure Monitor | Alerts (common alert schema) | Alert card |
| Google Cloud Monitoring | Incidents | Alert card |
| Pingdom | Check state changes | Alert card |
| updown.io | Checks going down and up | Notification |
| New Relic needs ?source=newrelic | Issues (classic webhook body) | Alert card |
| Better Stack needs ?source=betterstack | Incidents | Notification |
| Netdata | Alerts, and node reachability with ?source=netdata | Notification |
| Graylog | Event notifications | Notification |
| Amazon SNS | Notifications, such as CloudWatch alarms | Notification |
| Sentry | Issues, metric alerts, event alerts | Alert card for issues and metric alerts |
| Honeybadger | Faults, uptime, check-ins | Alert card |
| Rollbar | Items | Alert card |
| GitHub | Pushes, pull requests, issues, releases, check runs, workflow runs | Progress card for runs |
| GitLab | Pipelines, deployments, merge requests, issues, pushes | Progress card for pipelines and deployments |
| Bitbucket | Pushes, pull requests, commit statuses | Notification |
| Buildkite | Builds | Progress card |
| Drone | Builds | Progress card |
| Jenkins | Builds (Notification plugin) | Progress card |
| CircleCI | Finished workflows and jobs | Notification |
| Semaphore | Finished pipelines | Notification |
| Netlify | Deploys | Progress card |
| Docker Hub | Image pushes | Notification |
| Harbor | Artifact pushes, scans and other events | Notification |
| Flux | Notification controller events | Notification |
| Lidarr | Grabs, imports, failures, health | Alert card for health |
| Readarr | Grabs, imports, health | Notification |
| Whisparr | Grabs, imports, health | Alert card for health |
| Nextcloud | File, form and mail events (webhook_listeners) | Notification |
| Watchtower needs ?source=watchtower | Update reports (JSON template) | Notification |
A service missing here still works: its events arrive as notifications, described next.
Everything else: a notification
A payload no preset knows becomes one notification. The relay flattens the JSON into field paths such as data.check.name and picks the field that reads most like a title, the one that reads most like a body, and a link, by their names and what they hold. When the payload has no title of its own, the source is the title. When it has no body, the body lists up to four of its most readable fields. For example, a payload of only {"host":"nas-01","disk":"/srv","used":"93%","id":"8d3f5a1e-..."} posted with ?source=disk-check arrives as:
Disk check
Disk: /srv
Host: nas-01
Used: 93%Ids, timestamps and links are left out of those lines, and anything that looks like a credential, token, email address, card or phone number is masked. Each event is picked on its own, so a notification never depends on an earlier one.
Query parameters
The relay's per-request overrides work here too, next to source, and pass through to whichever route handles the request.
channels=notificationnever opens a card; card events arrive as notifications instead.channels=activitydrops notifications, so a payload that would be a notification delivers nothing.priority(0-10) sets the priority of cards the request opens.leveloverrides the interruption level of every notification the event sends.
https://relay.pushward.app/?source=alertmanager&channels=notification&level=time-sensitiveBagian ini menjelaskan fitur dalam pembaruan aplikasi yang sedang menunggu tinjauan App Store. Fitur ini akan otomatis terbuka di sini begitu pembaruan tersedia.
ack=1 makes the push of an alert repeat until someone acknowledges it, with ack_repeat and ack_expire setting the timing as on the provider routes. It applies to the events that open an alert card, also when channels=notification keeps the card closed, and the alert clearing stops the repeats. Progress cards and plain notifications are sent once, as before. The details, the 25-alert limit and the 400s are under acknowledged alerts on the Relay page.
https://relay.pushward.app/?source=alertmanager&ack=1&ack_repeat=120Like everything sent through the relay, these notifications are not end-to-end encrypted.
Responses
| Status | Meaning |
|---|---|
200 {"status":"ok"} | Delivered. |
200 ignored | The payload had no fields, such as {}. The detail field says why. |
200 ignored_activity | Sent as a notification, because a card had nothing to be keyed on. |
400 | The body is not a JSON object or array, or channels, priority or level is invalid. Fix the request rather than retrying. |
422 | source has characters other than lowercase letters, digits and dashes, or is longer than 32. |
401 / 403 | The key is missing, or PushWard rejected it. The key is only checked when there is something to deliver, so a bad key shows up on the first event, not when you save the webhook. |
413 | The body is over 1 MB. |
429 | Rate limited, by the relay or by PushWard. |
502 | PushWard refused the delivery or could not be reached. |
Limits
- Up to 256 fields per payload and 8 levels of nesting. Values are cut at 256 characters.
- Only the first element of an array is read. An Alertmanager group with three alerts is shown from the first one.
What the relay keeps
Nothing about your payloads. Each event is mapped and delivered on its own and then forgotten. While a preset's card is open, the relay keeps a hash of your key and of the value that keys the card, so the next event finds it; that entry goes when the card ends.
Self-hosted relay
The universal webhook is off by default on a self-hosted relay, and while it is off, POST / still hands recognised payloads to their providers and answers 404 for everything else. To turn it on:
| Variabel Lingkungan | Deskripsi | Default |
|---|---|---|
PUSHWARD_UNIVERSAL_ENABLED | Turn the universal webhook on (YAML: providers.universal.enabled) | false |
PUSHWARD_UNIVERSAL_PRESETS | Map the services above with their presets. Off, every payload arrives as a notification (YAML: providers.universal.presets) | true |