What a contact is
A contact is a place HostTracker can deliver an alert or a scheduled report to: an email address, a phone number, a chat app account, a webhook, an on-call integration key, and so on. Creating a contact does not alert anyone by itself - a monitor has to be subscribed to it first, and even then an unconfirmed contact receives nothing at all (see below).
Contact types
Section titled “Contact types”The API’s contact-type catalogue (GET /contact/type) publishes every type it knows about. Not all of them can
be created today - a few are registered for reads only (a stray/legacy row must still display correctly) but
hidden from creation:
| Type (API token) | Addressed by | Creatable via a plain address | Confirmable | Can receive reports |
|---|---|---|---|---|
email |
Email address | Yes | Yes (code) | Yes - the only type that can |
sms |
Phone number (international format) | Yes | Yes (code) | No |
voiceCall |
Phone number | Yes | Yes (code) | No |
http |
A URL you control, or a gateway-recognized webhook (Slack, Teams, PagerDuty, Opsgenie, Pushover, Pushbullet, Mattermost - see below) | Yes | No (born confirmed - there’s no channel to verify) | No |
webPush |
A browser push subscription | Yes, but only from the browser’s own subscription handshake, not a typed address | No (the browser step already proves it) | No |
telegram, viber, discord |
A messenger chat, linked by registering with the HostTracker bot | No - minted only by the bot’s registration handshake | No (linking proves it) | No |
facebook, googleChat |
Same as above | No, and hidden from the New Contact picker too | No | No |
skype |
Retired channel | No - reads only, for accounts that still hold one | No | No |
whatsApp |
Phone number, via the Meta Cloud API | Not yet - parked pending Meta onboarding, hidden from the picker for every account | Yes (once it ships) | No |
So in the app’s Add contact picker you see fourteen live options: Email, SMS, Call, HTTP (webhook), Slack, Microsoft Teams, PagerDuty, Pushover, Pushbullet, Mattermost, Telegram, Viber, Discord, and Web push. WhatsApp, Opsgenie, Skype, Facebook and Google Chat are excluded from that picker today (WhatsApp and Opsgenie because they aren’t fully wired up yet; Skype because it’s retired; Facebook and Google Chat by product decision even though the underlying bot channels exist). See all channels for a setup guide per type.
Confirmation - why an unconfirmed contact gets nothing
Section titled “Confirmation - why an unconfirmed contact gets nothing”Email, SMS and voice contacts must be confirmed before they receive anything real. This exists so a mistyped address can’t silently swallow alerts (or run up an SMS bill) forever.
- On create, HostTracker sends a 5-digit numeric code to the address, valid for 30 minutes with 3 attempts to enter it correctly. A still-valid, still-unused code is returned again on a resend request rather than replaced - so resending never invalidates a code you’re already looking at.
- Chat-app and key-addressed contacts (Telegram, Viber, Discord, PagerDuty, Opsgenie, Pushover, Pushbullet, webhooks, web push) are confirmed implicitly, by the setup step itself - there’s nothing separate to verify, because either the bot’s own registration handshake or the browser’s push-subscription exchange already proved the endpoint is real.
- If the account already holds a confirmed contact with the same type, address and delivery settings, a new one you create with that same address is born already confirmed - so adding a second alert-delay tier for a phone number you’ve already verified doesn’t ask you to re-verify it. Changing a contact’s address always resets it back to unconfirmed.
- The gate is silent and it’s enforced twice: first when HostTracker decides who should hear about an event at all (an unconfirmed or over-package-limit contact is dropped from that list before anything is rendered), and again right before sending. Nothing surfaces this as an error anywhere - a subscription can exist, look correctly configured, and simply never deliver. Always confirm a contact right after creating it, and send it a test alert to be sure.
Settings reference
Section titled “Settings reference”These are the fields on every contact, from the Main Settings group of the editor. A few (mimeType,
httpHeaders, templates) only apply to http contacts; plainText only to email.
| Setting (UI label) | API field (v2) | Type / allowed values | Default | Plan limits | What it does for you |
|---|---|---|---|---|---|
| Contact Type | type |
One of the tokens in the table above | - (required on create) | - | Selects the channel; cannot be changed after creation (type_immutable) |
| Address | address |
String - shape depends on type (email, E.164-ish phone, URL) |
- (required for address-bearing types) | - | Where the alert is delivered |
| Contact name | name |
String, up to 100 characters | Empty | - | A label to recognize it by later |
| Notification language | language |
2-letter code, or empty for “from profile” | From profile | - | Renders alert content in this language when a translation exists, else falls back to the profile language, then English. Voice scripts are English only regardless. |
| Alert delay | alertDelay |
Minutes - one of a fixed ladder: 0 (instant), 3, 5, 15, 30, 60, 180, 360, 720, 1440 |
0 (instant) |
- | How long a confirmed Down must persist before this contact hears about it - see escalation |
| Grouped alerts | groupedAlerts |
boolean | Email: true (also when POST /contact omits it); HTTP-family: false |
- | Combine alerts that fire close together into one message - see grouped alerts |
| Active hours | activePeriod |
{start, end, days[], timezone} or null |
null (always active) |
- | Restrict delivery to chosen hours/days/timezone - see Active hours |
| Billing notifications | billingNotifications |
boolean (email only) | false |
- | Also receive billing/payment emails at this address |
| News and updates | sendNews |
boolean (email only) | false |
- | Receive occasional product news |
| Plain-text emails | plainText |
boolean (email only) | false (HTML) |
- | Send plain text instead of the HTML design |
| Gateway | gateway |
String - a recognized value (e.g. Slack, Teams, PagerDuty, Opsgenie, Pushover, Pushbullet, Mattermost), or absent |
Server-routed (absent) | - | Pins an http contact to a specific channel’s formatting/delivery rules instead of a plain generic webhook |
| MIME type | mimeType |
String, e.g. application/json (http only) |
application/json |
- | The outgoing webhook body’s content type |
| HTTP headers | httpHeaders |
Array of {header, value} (http only) |
Empty | - | Custom headers sent with every webhook request (auth tokens, routing headers) |
| Custom templates | templates |
Array of {event, content}, event = up/down/repeatedlyDown (http only) |
Empty (uses the built-in payload) | - | Author the exact JSON/text HostTracker posts for each event - see Webhook for the [[token]] variables available |
Two members exist only on the wire, not as an editor field: defaultSubscriptions: {alerts, reports} (on
create only - seed this contact onto every existing monitor for Up+Down alerts and/or scheduled reports in
the same call) and inline alertSubscriptions[] / reportSubscriptions[] (subscribe specific monitors at
create time). Both are additive conveniences over calling the subscription endpoints separately afterward.
Set it up in the app
Section titled “Set it up in the app”- Open Alerts & Contacts in the sidebar and click + Add contact.
- Choose the Contact Type. The fields below it change to match - a typed address box for Email/SMS/Call, a bot-connect flow for Telegram/Viber/Discord, a browser-permission prompt for Web push, or a URL + Request Template group for HTTP/Slack/Teams/etc.
- Enter the address (or complete the connect flow) and give the contact a name.
- Expand Main Settings to set language, alert delay, active hours, and the type-specific switches from the table above.
- Click Save. For Email/SMS/Call, HostTracker sends the confirmation code immediately.
- Confirm it (link, code entry, or resend from the contact’s row), then send a test alert.
Do it with the API or MCP
Section titled “Do it with the API or MCP”Create an email contact:
POST /contact{ "type": "email", "address": "[email protected]", "name": "Ops inbox", "alertDelay": 0 }The response is the new ContactView, confirmed: false, plus a confirmation block ({sent, channel, expiresAt, triesAllowed}). Confirm it:
POST /contact/{id}/confirmation/verify{ "code": "48213" }Resend the code if it expired or wasn’t sent:
POST /contact/{id}/confirmationUpdate settings (partial - only the fields you send change):
PATCH /contact/{id}{ "alertDelay": 15, "groupedAlerts": true }List, read, delete: GET /contact, GET /contact/{id}, DELETE /contact/{id}. MCP tools:
create_contact (email, sms, voiceCall or webPush only - messenger contacts are registered from the messenger
itself, and http/webhook is deliberately excluded from this tool: use create_webhook under
Integrations for signed HTTP delivery instead), update_contact, delete_contact,
send_contact_confirmation, confirm_contact, list_contacts, get_contact, test_contact.
What happens next
Section titled “What happens next”A newly created contact is unconfirmed (except the implicitly-confirmed types) and has no subscriptions unless
you set defaultSubscriptions/inline subscriptions on create. It receives nothing until it’s both confirmed
and subscribed to at least one monitor for at least one event. Once both are true, it’s evaluated against
its own alert delay, active hours and grouping settings at send time - not at subscribe time.
Limits and gotchas
Section titled “Limits and gotchas”422 validation_failed(reasonunknown_member) - the create/update body has a closed vocabulary; an unrecognized top-level member, or a misspelled nested one (likeactivePeriod.timeZoneinstead oftimezone), is refused with anallowed[]list rather than silently dropped.422 type_immutable- you can’t changetypeafter creation. Create a new contact instead.422 validation_failed(reasonundeliverable_domain) - a new email address is checked for a working MX record at create/update time and refused if the domain can’t receive mail at all (this check fails open on DNS trouble, so it never blocks a real domain having a bad day).429 rate_limitedon a confirmation resend - capped at roughly 10 per contact per day and 50 per account per day, plus a short per-request cooldown; the response carriesRetry-After.422 invalid_confirmation_code- wrong, expired, or attempts exhausted; carriesattemptsLeftandexpiresAtso a client can tell a user exactly what’s wrong.409if the contact is already confirmed.- A contact can be deleted with everything it’s subscribed to -
DELETE /contact/{id}also removes its subscriptions. There is no undo. - Plan limits cap the total number of contacts and, per type, how many of each; an over-limit create either
refuses (
403 package_limiton v2) or, on the app’s create-anyway path, lands the contact paused (unconfirmable, no send) until you free up room.

