ntfy Compatibility
Crit Alarm is designed as a drop-in target for ntfy publishers. Any tool, library, or script that knows how to send notifications to an ntfy server can publish to Crit Alarm without changing code.
Key Differences from Upstream ntfy
Section titled “Key Differences from Upstream ntfy”The wire protocol matches ntfy. These four things differ on purpose:
- No Public Topics: Upstream ntfy allows publishing to arbitrary public topic names without authentication. Crit Alarm requires an explicit topic token (
tk_...) for every publish operation. Unauthenticated requests return401 Unauthorized. - Escalation into Incidents: When priority 5 is published to a topic with
critical: true, Crit Alarm opens an incident, starts a recurring repeat loop, and tracks two-stage acknowledgment. - No Scheduled Delivery: Crit Alarm explicitly rejects delayed messages (
X-Delay). - Polling vs. Streaming: In v1, message retrieval requires
poll=1(GET /{topic}/json?poll=1). Long-lived streaming endpoints (/sse,/ws, and/raw) return501 Not Implemented.
Supported Headers and Aliases
Section titled “Supported Headers and Aliases”Header names are case-insensitive. Each header supports standard ntfy aliases:
| Canonical Header | Aliases | Type | Default | Behavior |
|---|---|---|---|---|
X-Title |
Title, ti, t |
string | topic name | Title displayed on the mobile lock screen. |
X-Priority |
Priority, prio, p |
1 to 5 or name |
3 |
Priority level. Level 5 opens an incident on critical topics. |
X-Tags |
Tags, tag, ta |
comma list | none | Stored and displayed in the app. Emoji shortcodes are rendered. |
X-Click |
Click |
URL | none | Web URL opened when the alert notification is tapped. |
X-Markdown |
Markdown, md |
true, 1, yes |
off | Renders the notification body as Markdown in the app. |
Query Parameter Shorthands
Section titled “Query Parameter Shorthands”Parameters can also be specified in the query string:
?t=or?title=Title?p=or?priority=Priority (1to5orurgent,high,default,low,min)?ta=or?tags=Comma-separated tags?m=or?message=Message text
Headers Accepted and Ignored
Section titled “Headers Accepted and Ignored”Many monitoring tools and libraries include extra ntfy headers by default. To maintain full compatibility without throwing unexpected HTTP errors, Crit Alarm accepts and ignores the following headers in v1:
X-Actions(custom notification action buttons)X-Attach(binary file attachments)X-Filename(attachment filename)X-Icon(custom notification avatar/icon)X-Email(forwarding to email)X-Call(phone call integration)X-Template(ntfy templating)X-Cache(caching directives)X-Firebase(upstream FCM overrides)X-UnifiedPush(UnifiedPush discovery headers)
Requests carrying these headers return 200 OK, so upstream tools keep working.
Deliberate Rejection of X-Delay
Section titled “Deliberate Rejection of X-Delay”X-Delay and its aliases (At, In, or JSON field delay) are explicitly rejected with HTTP 400 Bad Request:
{ "code": 40000, "http": 400, "error": "scheduled delivery not supported"}Why X-Delay is rejected
Section titled “Why X-Delay is rejected”Returning 200 OK for a delayed alert the server cannot schedule is dangerous:
- Delivering the alert immediately causes false alarms at the wrong time.
- Dropping the delay and never alerting causes catastrophic missed outages.
Rejecting the request with an explanatory error informs the calling service immediately that scheduled delivery is unsupported.
Response Object Compatibility
Section titled “Response Object Compatibility”The JSON response returned by POST /{topic} matches ntfy’s message object:
{ "id": "m_7f3k2p9q", "time": 1757462400, "expires": 1757505600, "event": "message", "topic": "prod", "title": "Uptime Kuma", "message": "db01 is down", "priority": 5, "tags": ["warning"], "incident_id": "inc_9a8b7c"}Because incident_id is an additive field, existing ntfy SDKs in Go, Python, Node.js, and other languages parse this response successfully without schema errors.