Skip to content

Get started

Most read

Email, Discord, Slack

Who receives what, through which channel, and why an alert sometimes doesn't go out.

Updated on 25 September 2026

On this page

An alert goes out when a URL fails, when it recovers, when its content changed after a deploy, or when the domain's DNS moved. Email is the base channel, on all plans. Discord and Slack, on every plan, and the outbound webhook, on a paid plan, receive the same thing in addition, project by project. Nothing is sent as long as everything is green: it's the product's principle, not an option.

One alert per incident, on each person's channel, and the recovery that follows.

What PostShip sends

4 kinds of messages, with the same label everywhere:

KindLabelWhen
failFailingA URL just went into failure (or the outage changed nature: a 503 turned 404)
recoveredRecoveredThe URL goes back to green, and a failure alert had indeed gone out before
mutatedContent changedWhat changed, a latency anomaly or a third-party script that changed
dnsDNS driftThe domain's records changed since the last deploy

Each item carries the URL, a sentence naming the cause (“The page answers 200 but a static file is missing: /app.js.”, “The price no longer appears on …”), the HTTP status and the TTFB, and a link to the URL's detail. Each sentence comes from a table of codes, the same on all channels; nothing is generated by a model.

The email subject

Project name — 2 URLs failing, or — 1 URL recovered, or — DNS drift detected. The body starts with the recap (“2 failing, 0 recovered.”) then one card per URL. When the alert follows a deploy, the recap says “Since the last deploy: …”.

When several URLs go down together

From 3 URLs going down at the same time for the same reason — the server doesn't respond, or it answers the same 5xx error — PostShip doesn't make 3 cards but a single one, titled Site unreachable · 7 URL or Server error 503 · 7 URL, with the matching sentence: “7 URLs stopped responding at the same time: it's the whole site, not these pages. Look at the host or the DNS before the pages.” The list stops at 6 URLs, then “… and 3 more”. A content failure (missing tag, missing file) is never grouped: it isn't a site outage.

“It may not be you”

When something goes down, PostShip reads the state of the providers your site uses (Vercel, Cloudflare, Supabase…). If one of them reports an incident, the alert adds under the recap: “It may not be you: Vercel reports an incident (Elevated errors on deployments).” It's the first thing to know before searching on your side.

Set it up

  • Email: Account → Notifications. 3 checkboxes: “A URL fails” (unticking turns off all alert emails), “A URL is recovered”, “Content changed after a deploy”. These boxes only concern email.
  • Discord, Slack: Project → Settings → Integrations, Outgoing section, one card per channel. See Connect Discord, Connect Slack. These channels receive everything, recoveries included.
  • Test: the “Send a test alert” button on Integrations sends a real alert, on all connected channels, respecting the project's rules. 3 tests per minute at most.

What triggers an alert, and what holds it back

A failure alert goes out at the transition: when the streak of consecutive failures reaches the number chosen in Rules (1 by default). A page down all night writes once, not 144 times. It writes again only if the outage changes nature. An identical alert (same URL, same fingerprint) is never sent again in less than 10 minutes.

What holds a send back, on all channels at once:

  • Muted alerts (“Mute 1 h / 4 h / 24 h” on the Incidents page or in Rules).
  • A maintenance window, one-off or recurring, in progress.
  • The project's quiet hours.
  • The silencing of a precise URL (“Mute alerts for 4 h” in a URL's menu): only that URL is removed from the message.

In all these cases the check did run and the history is written: it's the sending that stops, not the monitoring.

Limits and plans

DiscoverProPro Plus
EmailYesYesYes
Discord, SlackYesYesYes
Outbound webhookNoYesYes
Indexability and DNS drift alertsNo (visible in the app)YesYes

See the plans.

Troubleshooting

Why did the email arrive but not the Discord message?

A webhook deleted on Discord's side answers 404: PostShip treats it as a failure, doesn't record it as sent, and the email goes out anyway. Reconnect the channel from Integrations. Each channel is independent: one's outage doesn't prevent the others.

Why don't I receive recoveries?

Either the “A URL is recovered” box is unticked on your account, or no failure alert had gone out for that outage (for instance with a confirmation at 3 failures and a 2-run outage): PostShip doesn't announce the recovery of an incident it never reported to you.

Connect Discord

Receive alerts in a Discord channel by pasting a webhook address. On every plan.

Discord receives alerts through a webhook: an address Discord creates for a channel, which you paste into PostShip. No bot is added to the server, and it's included in every plan, Discover too. All it takes is someone with the “Manage webhooks” permission giving you the address.

Create the webhook

The webhook is created from Discord, in the channel's settings.

  1. In Discord, right-click the channel → Edit channel → Integrations → Webhooks.
  2. Create a webhook, give it a name (“PostShip”), then click “Copy webhook URL”.
  3. In PostShip, open Project → Settings → Integrations, paste the URL in the Discord card and save. Only a https://discord.com/api/webhooks/... address is accepted.

“Test alerts”, on the same page, sends a test message to the channel.

What you receive

One message per check that changes something, posted under the name “PostShip”: a box coloured by state (red for failing or DNS drift, green for recovered, orange for content changed), the title (“2 URLs failing”, “Site unreachable · 7 URL”), the recap, then one field per URL with the failure reason in plain words, the HTTP status and the TTFB, and a link to the URL's page. At the foot: “Dashboard · Incidents · Manage alerts”. Beyond 8 URLs in the same message, the others are counted (“+3 more URLs on the dashboard”). The detail of the labels is on the alert channels.

The same channel also receives the team messages, in plain text: “marie takes charge of the incident” (taking charge), the escalation and, on a paid plan, the daily digest.

Disconnect or change channel

The “Disable” button deletes the saved URL: PostShip immediately stops writing there. To change channel, paste the new channel's webhook instead. To silence alerts without disconnecting anything, use “Mute 1 h / 4 h / 24 h”, the quiet hours or a maintenance window.

Limits and plans

DiscoverProPro Plus
Discord alertsYesYesYes
Daily digest in the channelNoYesYes

The plan that counts is the project owner's. See the plans.

Troubleshooting

Why is the URL refused?

Only https://discord.com/api/webhooks/... addresses are accepted. A server invite link or a channel's address isn't a webhook: follow the steps above to create one.

Why does an @everyone in my alert mention nobody?

Deliberate: what comes from your site (a page title, an excerpt of changed content) is neutralised before being written in the message, so that a text fetched from a monitored page never rings the whole team.

Connect Slack

Receive alerts in a Slack channel by pasting an incoming webhook address. On every plan.

Slack receives alerts through an incoming webhook: an address Slack gives you for a channel, which you paste into PostShip. It's included in every plan, Discover too.

Create the webhook

The incoming webhook is created from your own Slack application.

  1. Go to https://api.slack.com/apps and create an application (“From scratch”), attached to your workspace.
  2. In the left menu, open “Incoming Webhooks” and enable the option.
  3. Click “Add New Webhook to Workspace”, choose the channel, authorise, then copy the URL starting with https://hooks.slack.com/services/.
  4. In PostShip, open Project → Settings → Integrations, paste the URL in the Slack card and save. Only a hooks.slack.com address is accepted.

“Test alerts”, on the same page, sends a test message to the channel.

What you receive

A structured message: a title with the project and the state (“My site — 2 URLs failing”), a reminder of the number of failing, recovered or changed URLs, one section per URL with the failure reason in plain words, the HTTP status and the TTFB, and 3 buttons: “Open the dashboard”, “Incidents”, “Manage alerts”. The main button turns red when something is failing or a DNS drift is detected. Beyond 8 URLs, the others are counted. The detail of the labels is on the alert channels.

The same channel also receives the team messages in plain text: taking charge, escalation and, on a paid plan, the daily digest.

Disconnect or change channel

The “Disable” button deletes the saved URL. To change channel, create a webhook for the new channel and paste it instead: a Slack incoming webhook is tied to a single channel. To silence alerts without disconnecting anything, see Rules and Maintenance.

Limits and plans

DiscoverProPro Plus
Slack alertsYesYesYes
Daily digest in the channelNoYesYes

The plan that counts is the project owner's. See the plans.

Troubleshooting

Why is the URL refused?

Only https://hooks.slack.com/... addresses are accepted. A channel's address (https://acme.slack.com/archives/...) isn't a webhook: follow the steps above to create one.

Why does my Slack message only show 8 URLs?

Slack limits the size of a message. The following URLs are counted (“+4 more URLs — see the dashboard”) and the Incidents page lists them all.

Outbound webhook

Available on the Pro and Pro Plus plans.

Receive every alert as HMAC-signed JSON on your own endpoint, and choose the events.

In addition to email, Discord and Slack, PostShip can send every alert as a POST to an HTTPS URL of yours, signed with HMAC-SHA256. It's the channel for automations: open a ticket, cut a deploy, turn on a lamp. It obeys the same rules as the other channels (silence, quiet hours, confirmation, maintenance) because it receives exactly the same batch of items, once filtered.

What PostShip sends

One request per kind of event: a batch that mixes a failure and a recovery becomes 2 requests, one fail and one recovered.

POST /hooks/postship HTTP/1.1
Content-Type: application/json
X-PostShip-Event: fail
X-PostShip-Version: 1
X-PostShip-Delivery: 6d0c1a2e-…
X-PostShip-Signature: sha256=3f1a…e9c2
{
  "version": 1,
  "id": "6d0c1a2e-…",
  "event": "fail",
  "projectId": "8b2f…",
  "projectName": "My site",
  "at": "2026-09-11T14:03:12.418Z",
  "items": [
    { "url": "https://mysite.fr/checkout", "httpStatus": 503, "missing": null },
    { "url": "https://mysite.fr/", "httpStatus": 200, "missing": ["asset:script:/app.js"] }
  ],
  "test": false
}
FieldValue
versionThe payload version, 1. It only changes when something breaks: an added field doesn't change it, a renamed or removed field does
idThe delivery id, also in X-PostShip-Delivery. A replay keeps the same one: deduplicate on it
eventfail, recovered, mutated or dns
projectId, projectNameThe project
atThe time of sending, ISO 8601 in UTC
items[].urlThe URL concerned (the host name for dns)
items[].httpStatusThe HTTP status, or null without a response
items[].missingThe failure codes (asset:…, price_token, meta_noindex…), or null
testtrue only for the “Send a test” button

The signature

X-PostShip-Signature is sha256= followed by the hexadecimal HMAC-SHA256 digest of the request's raw body, computed with your secret. Verify it before reading the content: without it, anyone who knows the URL can make you open a ticket.

Verify the signature
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody, signature, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

The body must be read as is (raw text) before any JSON decoding: the signature covers the bytes sent, and a re-serialisation changes the order of the keys or the whitespace.

Replay

Every delivery is kept as sent — the last 20 per project, with the status received — in the Outbound webhook card. “Replay” sends the same body under the same id, signed with the current secret, with an extra X-PostShip-Replay: true header. A receiver that deduplicates on id won't open 2 tickets; a receiver that was down gets what it missed. Replaying is a project editor's action, never automatic.

What PostShip requires of your endpoint

  • A public HTTPS URL. A private or local address, or one that resolves to an internal network, is refused at registration, and again on every send.
  • A 2xx response in under 4 seconds. Beyond that, the send is abandoned, without retry.
  • No redirect: a 3xx isn't followed, it counts as a failure. The signed body must not be handed to another host than the one you declared.

An endpoint that fails prevents neither the other channels nor the next run: the error is noted on PostShip's side, nothing else.

Set it up

Project → Settings → Integrations, “Outgoing” section, “Outbound webhook” card.

  1. Paste the URL in “Outbound webhook URL” and save.
  2. Click “Regenerate the secret”. The secret (64 hexadecimal characters) is shown only once: “Copy this secret now — it will never be shown again.” Store it in an environment variable on your side. As long as no secret exists, nothing is sent.
  3. Click “Send a test”: a fail request with a single https://example.com item in 500 and "test": true. Your endpoint can thus tell a probe from a real incident.
  4. Choose the “Events sent”: Failure, Recovery, Change, DNS. All ticked by default. Unticking everything is refused: “Choose at least one event — or disable the webhook.”

“Disable” erases the URL and the secret. “Regenerate the secret” invalidates the old one immediately.

What triggers a send

Exactly what triggers an alert on the other channels, see Email, Discord, Slack and Rules: failure transition, recovery of a reported incident, content changed after deploy, DNS drift. Sends held back by silence, quiet hours or a maintenance aren't replayed. Sorting by event happens here and nowhere else: the other channels receive everything.

Limits and plans

DiscoverProPro Plus
Outbound webhookNoYesYes

See the plans. To read a project's state rather than waiting for it to write to you, see the API.

Troubleshooting

Why does “Send a test” answer “Set the URL first and generate a secret”?

Both are needed: without a secret, PostShip doesn't sign, so doesn't send. Click “Regenerate the secret”.

Why does the signature never match?

You're probably verifying the re-serialised JSON rather than the raw body. Read the body as text before JSON.parse, compute the HMAC on it, and compare with the value after sha256=.

Why does my endpoint receive fail but never recovered?

Look at the “Events sent” boxes. And a recovery is only sent if the failure had been: see Rules.

Daily digest

Available on the Pro and Pro Plus plans.

A message every morning at 8 am on your channels — the night's rate, open incidents, yesterday's deploys.

An alert says something is happening; silence doesn't say everything is fine, it says just as well that PostShip went down. A message at a fixed time, every day, is the only proof that a silence is a good silence. And for a team, it's the morning check-in without a meeting: the night's rate, what is still red, what was deployed. It goes out on the project's channels, never by email.

What PostShip sends

At 8 am, in the project's time zone, on each connected channel (Discord, Slack), a text message:

An ordinary morning
All green — My site
Success rate over 24 h: 99.7% (720 checks)
No production deploy yesterday.
Error budget (99.9%): 3 h 12 min left.
https://postship.fr/…
A morning with an incident
1 ongoing incident — My site
Success rate over 24 h: 96.2% (720 checks)
• https://mysite.fr/checkout — /checkout answers 503.
2 production deploys over 24 h.
https://postship.fr/…

Line by line:

LineWhere it comes from
The title“All green” or “N ongoing incidents”, preceded by a green or red dot, and the project name
The rateSuccessful runs over the last 24 h, out of the total; “No check in the last 24 h.” if there was none
The incidentsUp to 5 failing URLs with the sentence naming the cause, then “… and N more”
The deploysThe production deploys recorded over 24 h, see Deploy webhooks
The error budgetOnly if a target is set (Settings → Monitoring, “Uptime target” row): the downtime you have left over the window, or “exceeded”
The linkThe project's dashboard

Short, on purpose: you read it on a phone.

Set it up

Project → Alerts → Notifications, “Every morning” section — or under the 3 channels, in Project → Settings → Integrations: the “Digest every morning at 8 am” switch. It saves by itself. Without any connected channel, it stays greyed out and the row says so: “Connect a channel first.”

The time isn't adjustable, the time zone is: it's the project's quiet hours zone (Project → Alerts → Rules, “Quiet hours” card, Time zone field), the only time zone a project knows. Without a setting, Europe/Paris.

When it goes out

PostShip's engine runs every 2 minutes, whatever the plan. The digest goes out on the first run after 8 am local time that finds it hasn't gone out yet today: a run missed at 8:00 doesn't push the digest to tomorrow, it goes out at 8:05. One per local calendar day, whatever the number of runs; 2 overlapping runs cannot send it twice.

It goes out even if everything is green: that's its role. It also goes out during quiet hours, a maintenance or a “Mute 24 h”: an appointment isn't muted like an alert. A channel that answered an error (webhook deleted) doesn't block the others.

Limits and plans

DiscoverProPro Plus
Daily digestNoYesYes

The plan that counts is the project owner's. A project that fell back to Discover keeps its setting but no longer receives anything, like its channel alerts. See the plans.

Troubleshooting

Why does the digest arrive at 9 am?

The project's time zone isn't yours. Set the quiet hours' Time zone field in Rules: the digest follows it.

Why didn't the digest arrive this morning?

3 possible causes: no connected channel (the checkbox flags it), all channels refused the message (webhook deleted, bot removed from the group: reconnect from Integrations), or the owner's plan no longer allows it.

Why does the digest's rate differ from the Status page's?

The digest counts all the project's runs over 24 h, all URLs together. The status page only counts the components it displays, over its own window. See Status page.