Help

Notifications and webhooks

In short: open Settings and find Notifications. Turn on the emails you want, or add a channel for Discord, Slack, Telegram, ntfy or your own webhook and pick what it gets. Everything is off until you turn it on, and you can turn anything off again at any time.

What you can get

Three emails, sent to your account's email address:

  • Dead links: one email when hrva.cc marks one or more of your links dead.
  • Weekly summary: last week's clicks, every Monday morning.
  • Expiry reminders: an email a day before one of your links expires.

Four events you can send to a channel:

  • A link stopped working: checked every night, sent once when a link is marked dead.
  • A link works again: sent when a dead link answers again.
  • Daily click summary: yesterday's clicks on your links, sent after midnight, and skipped when there were none.
  • Weekly summary: last week's clicks, every Monday morning.

Nothing is on by default, and nothing is sent until you turn it on. Your dashboard shows dead links whether or not you turn anything on.

Email

  1. Sign in and open Settings. Under Notifications, the Email section shows the address the emails go to.
  2. Turn on the switch for each email you want: Dead links, Weekly summary or Expiry reminders. Each switch says what it sends, and once it's on, On since shows the date you turned it on.

The weekly summary has your clicks compared with the week before, your top links, links that stopped working that week and links that end soon: they expire within 7 days, or have 10% or fewer of their visits left. A week with no clicks and nothing to report sends nothing. The daily click summary and A link works again aren't sent by email; add a channel for those.

Expiry reminders used to be sent to everyone. They're now off until you turn them on, like the other two.

Unsubscribe

  1. Open the link at the bottom of the notification email.
  2. On the page that opens, select Unsubscribe. It says, for example, Done. You won't get weekly summary emails any more.

If that email was already off, the page says so, for example Weekly summary emails were already off. You don't need to sign in. Mail apps that show their own unsubscribe button turn the email off in one click too. Or turn the switch off in Settings, under Notifications.

Emails about your account itself, such as address verification, password reset, security notices and a link being blocked, aren't notifications and can't be turned off.

Every night hrva.cc checks where each active link goes. A link is marked dead when its destination fails in one of these ways on 3 different nights, with no working answer in between:

  • the page wasn't found (404) or was removed (410)
  • the website's domain doesn't exist
  • the website refused the connection
  • the website's secure connection failed

Slow answers, server errors, rate limits and pages behind a login or a bot check never count. They don't move a link towards dead, and they don't reset the count either.

A dead link shows Destination looks dead on your URLs page and in the link's analytics, with the date and the reason, for example The page wasn't found (404). The badge shows only while the link is active.

The badge goes away by itself on the first night the destination works again. If the page moved, shorten its new address and turn the old link off. You can't change where an existing short link points; only an admin can, and that clears the badge at once.

Links made without an account are checked too, and only the admin sees their result.

If you run a website and found this page in your logs, this is what the checker does:

  • It sends a HEAD request to each destination. When the answer needs confirming, it sends a small GET that asks for the first 1 KB only.
  • It runs from hrva.cc's server in Oracle Cloud, Frankfurt.
  • It checks each link at most once a night, and sends at most one request every 5 seconds to any one website. It follows up to 5 redirects.
  • It identifies itself with the User-Agent hrva.cc-linkcheck/1.0 (+https://app.hrva.cc/help/notifications#link-checker).
  • It sends no cookies and no visitor data. It never opens the short link itself, so a check never counts as a click.

Questions or problems with the checker: email abuse@hrva.cc.

Channels

A channel sends notifications to a chat app or to your own server. Under Chat apps and webhooks in Settings:

  1. Select Add channel.
  2. Choose the Type: Discord, Slack, Telegram, ntfy or Webhook (signed JSON).
  3. Give it a Name you'll recognise, such as Team alerts, up to 60 characters.
  4. Fill in the type's fields: Webhook URL for Discord and Slack, Bot token and Chat ID for Telegram, Topic URL and Access token (optional) for ntfy, and URL for a webhook. How to get this links to the steps below. If you paste an address that belongs to another type, the form says so, for example This looks like a Discord URL., with Switch to Discord.
  5. Under Send me, tick the events this channel should get. None is ticked to start with, and while none is, the dialog says the channel won't get any messages.
  6. Select Add channel, then Send test on the new channel. It says Sent. Check Discord. (or Slack, Telegram, ntfy or your webhook, for those types), or why the test failed.

Each channel shows its address masked, its events and its last delivery: No deliveries yet., Last delivered with the time, or Last delivery failed with the time and the reason. Its switch pauses the channel without deleting it: On turns to Off. Edit changes its name, address and events; saved addresses and tokens stay hidden, and under each of those fields it says Saved. Leave empty to keep it. A channel's type can't be changed: to change the type, add a new channel. Delete removes the channel, and it stops getting notifications at once.

You can have up to 10 channels.

Discord

  1. In Discord, open the settings of the channel the messages should go to (or Server Settings), then Integrations, then Webhooks. You need the Manage Webhooks permission.
  2. Select New Webhook, check that it posts to the right channel, and select Copy Webhook URL.
  3. In hrva.cc, add a channel with the type Discord and paste the address into Webhook URL. It starts with https://discord.com/api/webhooks/.

Messages never ping anyone and show no link previews.

Slack

  1. Go to api.slack.com/apps, select Create New App, then From scratch, name it (for example hrva.cc) and pick your workspace.
  2. Open Incoming Webhooks and turn on Activate Incoming Webhooks.
  3. Select Add New Webhook, pick the channel and allow it. Copy the new Webhook URL.
  4. In hrva.cc, add a channel with the type Slack and paste the address into Webhook URL. It starts with https://hooks.slack.com/services/.

Telegram

  1. In Telegram, open @BotFather, send /newbot and choose a name and a username for the bot. BotFather answers with a token like 123456789:AAH4Fq2xYzExample. Paste it into Bot token.
  2. Add the bot to the group that should get the messages, or make it an admin of your channel. For messages to yourself, open a chat with the bot and select Start.
  3. Fill in Chat ID. For a public channel, that's its name, like @mychannel. Otherwise, send a message in the chat (in a group, send /start), then open https://api.telegram.org/bot<your token>/getUpdates in your browser and copy the number after "chat":{"id":. Group and channel IDs start with a minus sign, like -1001234567890.
  4. In hrva.cc, add a channel with the type Telegram.

If a test says Telegram refused the bot token, check the token with BotFather.

ntfy

  1. Pick a topic name that's hard to guess, such as hrva-7f3k9q2m. Anyone who knows a topic's name on ntfy.sh can read it.
  2. Subscribe to the topic in the ntfy app on your phone or computer.
  3. In hrva.cc, add a channel with the type ntfy and enter the Topic URL, like https://ntfy.sh/hrva-7f3k9q2m. A topic on your own ntfy server works too, as long as the server has a public https address.
  4. If the topic needs a login, create an access token in ntfy (under Account, then Access tokens) and paste it into Access token (optional). Otherwise leave it empty.

Webhooks (signed JSON)

A webhook channel sends a JSON POST to your own https address, signed so you can check that it came from hrva.cc. Add a channel with the type Webhook (signed JSON) and enter its URL. It must be a public https address, and not a Discord, Slack, Telegram or ntfy.sh address: for those, choose that type instead, so messages arrive formatted.

After you add it, Your signing secret appears at the top of Chat apps and webhooks. This is the only time it's shown: select Copy secret, store it where your server can read it, then select I've saved it.

Every request has these headers:

Content-Type: application/json
X-Hrva-Event: link.dead
X-Hrva-Delivery: 5b0f8c2e-4d1a-4f7e-9a63-2c8e1d7b9f40
X-Hrva-Signature: sha256=<64 lowercase hex characters>
  • X-Hrva-Event: link.dead, link.back, summary.daily, summary.weekly, or test for Send test.
  • X-Hrva-Delivery: the delivery's ID, the same as deliveryId in the body.
  • X-Hrva-Signature: sha256= and the lowercase hex HMAC-SHA256 of the raw body, keyed with your signing secret.

This is the body when a link stops working (the other events carry their own fields, such as backOn for link.back and totals for the summaries):

{
  "event": "link.dead",
  "deliveryId": "5b0f8c2e-4d1a-4f7e-9a63-2c8e1d7b9f40",
  "createdAt": "2026-10-27T01:14:00Z",
  "links": [
    {
      "shortUrl": "https://hrva.cc/abc",
      "destinationHost": "example.com",
      "deadSince": "2026-10-27",
      "lastStatus": "404"
    }
  ]
}

Check the signature

Use the raw body, before parsing. Parsing and re-encoding the JSON changes its bytes, and the signature no longer matches. Compare in constant time, as both examples do.

Python:

import hashlib
import hmac

def signature_is_valid(secret: str, body: bytes, header: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

# body is the raw request body, before any JSON parsing
# header is the X-Hrva-Signature header

Node.js:

const crypto = require("node:crypto")

function signatureIsValid(secret, rawBody, header) {
  const expected = Buffer.from(
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex"),
  )
  const received = Buffer.from(header || "")
  return expected.length === received.length && crypto.timingSafeEqual(expected, received)
}

// rawBody is the request body as a Buffer, before JSON.parse

Answer with any 2xx status within 10 seconds. hrva.cc doesn't follow redirects, so a 3xx counts as a failure. A delivery that gets no answer, times out, or gets 408, 429 or a 5xx is tried again 1, 10 and 60 minutes later, 4 tries in all; any other answer is not retried. A retry has the same X-Hrva-Delivery and createdAt, so you can spot repeats and handle each delivery once.

If the secret leaks, select New signing secret on the channel. The old secret stops working at once, and the new one is shown once, like the first.

When a channel stops working

When a delivery fails, the channel shows Last delivery failed and the reason, even while hrva.cc is still trying it again. A failure that may pass (no answer, a timeout, or a 408, 429 or 5xx) is tried again 1, 10 and 60 minutes later, so for about an hour, and the line changes to Last delivered if a try gets through. Only a delivery hrva.cc gives up on counts towards the 10 days: one whose last try failed, or one that got any other answer. If that happens on 10 different days with no successful delivery in between, the channel turns itself off and says Turned off on the date after failing for 10 days. Fix the channel, then turn it on.

  1. Fix the cause, for example a webhook someone deleted in Discord: create a new one and paste it with Edit.
  2. Use Send test to check it. Tests don't count towards the 10 days.
  3. Turn the channel back on with its switch, so it says On again.

Notifications and your privacy

  • Emails and channel messages carry counts, your short links, their destination hosts and dates, never your visitors' IP addresses, browsers or referrers, and never your email address.
  • Channel addresses, bot tokens, access tokens and signing secrets are encrypted when saved. After that, addresses and bot tokens are shown masked, and access tokens and signing secrets aren't shown again.
  • Each time you turn a notification on or off, hrva.cc keeps a record of when and how, as proof of your choice, until you delete your account.
  • Each delivery to a channel is kept for 30 days, to retry failures and show you the last result.
  • The data export in Settings includes your consent history and your channels: masked addresses, the Telegram chat ID, and when each channel last delivered or turned off. It never includes tokens or secrets.

The Privacy Policy has the details.