---
obj: application
website: https://ntfy.sh
repo: https://github.com/binwiederhier/ntfy
---

# ntfy
ntfy (pronounced "notify") is a simple HTTP-based pub-sub notification service. With ntfy, you can send notifications to your phone or desktop via scripts from any computer.

## Publishing
Publishing messages can be done via HTTP PUT/POST or via the ntfy CLI. Topics are created on the fly by subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick something that's not easily guessable.

Here's an example showing how to publish a simple message using a POST request:

```sh
# Command line (curl):
curl -d "Backup successful 😀" ntfy.sh/mytopic

# ntfy CLI
ntfy publish mytopic "Backup successful 😀"
```

### Message title
The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title, you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).

```sh
curl -H "X-Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
curl -H "Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
curl -H "t: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial

ntfy publish \
    -t "Dogs are better than cats" \
    controversial "Oh my ..."
```

### Message priority
All messages have a priority, which defines how urgently your phone notifies you. On Android, you can set custom notification sounds and vibration patterns on your phone to map to these priorities.

The following priorities exist:

| Priority             | ID  | Name           | Description                                                                                            |
| -------------------- | --- | -------------- | ------------------------------------------------------------------------------------------------------ |
| Max priority         | `5` | `max`/`urgent` | Really long vibration bursts, default notification sound with a pop-over notification.                 |
| High priority        | `4` | `high`         | Long vibration burst, default notification sound with a pop-over notification.                         |
| **Default priority** | `3` | `default`      | Short default vibration and sound. Default notification behavior.                                      |
| Low priority         | `2` | `low`          | No vibration or sound. Notification will not visibly show up until notification drawer is pulled down. |
| Min priority         | `1` | `min`          | No vibration or sound. The notification will be under the fold in "Other notifications".               |

You can set the priority with the header `X-Priority` (or any of its aliases: `Priority`, `prio`, or `p`).

```
curl -H "X-Priority: 5" -d "An urgent message" ntfy.sh/phil_alerts
curl -H "Priority: low" -d "Low priority message" ntfy.sh/phil_alerts
curl -H p:4 -d "A high priority message" ntfy.sh/phil_alerts

ntfy publish \ 
    -p 5 \
    phil_alerts An urgent message
```

## Tags & emojis 🥳 🎉
You can tag messages with emojis and other relevant strings:

* **Emojis**: If a tag matches an emoji short code, it'll be converted to an emoji and prepended to title or message.
* **Other tags:** If a tag doesn't match, it will be listed below the notification.

This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script names, hostnames, etc.). Use the emoji short code list to figure out what tags can be converted to emojis.
Here's an **excerpt of emojis** I've found very useful in alert messages:

<table class="remove-md-box"><tr>
<td>
    <table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
    <tr><td><code>+1</code></td><td>👍</td></tr>
    <tr><td><code>partying_face</code></td><td>🥳</td></tr>
    <tr><td><code>tada</code></td><td>🎉</td></tr>
    <tr><td><code>heavy_check_mark</code></td><td>✔️</td></tr>
    <tr><td><code>loudspeaker</code></td><td>📢</td></tr>
    <tr><td>...</td><td>...</td></tr>
    </tbody></table>
</td>
<td>
    <table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody> 
    <tr><td><code>-1</code></td><td>👎️</td></tr>
    <tr><td><code>warning</code></td><td>⚠️</td></tr>
    <tr><td><code>rotating_light</code></td><td>️🚨</td></tr>
    <tr><td><code>triangular_flag_on_post</code></td><td>🚩</td></tr>
    <tr><td><code>skull</code></td><td>💀</td></tr>
    <tr><td>...</td><td>...</td></tr>
    </tbody></table>
</td>
<td>
    <table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
    <tr><td><code>facepalm</code></td><td>🤦</td></tr>
    <tr><td><code>no_entry</code></td><td>⛔</td></tr>
    <tr><td><code>no_entry_sign</code></td><td>🚫</td></tr>
    <tr><td><code>cd</code></td><td>💿</td></tr> 
    <tr><td><code>computer</code></td><td>💻</td></tr>
    <tr><td>...</td><td>...</td></tr>
    </tbody></table>
</td>
</tr></table>

You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, `tag`, or `ta`). Specify multiple tags by separating them with a comma, e.g. `tag1,tag2,tag3`.

```
curl -H "X-Tags: warning,mailsrv13,daily-backup" -d "Backup of mailsrv13 failed" ntfy.sh/backups
curl -H "Tags: horse,unicorn" -d "Unicorns are just horses with unique horns" ntfy.sh/backups
curl -H ta:dog -d "Dogs are awesome" ntfy.sh/backups

ntfy publish \
    --tags=warning,mailsrv13,daily-backup \
    backups "Backup of mailsrv13 failed"
```

## Markdown formatting
You can format messages using [Markdown](https://www.markdownguide.org/basic-syntax/) 🤩. That means you can use **bold text**, *italicized text*, links, images, and more. Supported Markdown features (web app only for now):

- [Emphasis](https://www.markdownguide.org/basic-syntax/#emphasis) such as **bold** (`**bold**`), *italics* (`*italics*`)
- [Links](https://www.markdownguide.org/basic-syntax/#links) (`[some tool](https://ntfy.sh)`)
- [Images](https://www.markdownguide.org/basic-syntax/#images) (`![some image](https://bing.com/logo.png)`)
- [Code blocks](https://www.markdownguide.org/basic-syntax/#code-blocks) (` ```code blocks``` `) and [inline code](https://www.markdownguide.org/basic-syntax/#inline-code) (`` `inline code` ``)
- [Headings](https://www.markdownguide.org/basic-syntax/#headings) (`# headings`, `## headings`, etc.)
- [Lists](https://www.markdownguide.org/basic-syntax/#lists) (`- lists`, `1. lists`, etc.)
- [Blockquotes](https://www.markdownguide.org/basic-syntax/#blockquotes) (`> blockquotes`)
- [Horizontal rules](https://www.markdownguide.org/basic-syntax/#horizontal-rules) (`---`)

By default, messages sent to ntfy are rendered as plain text. To enable Markdown, set the `X-Markdown` header (or any of its aliases: `Markdown`, or `md`) to `true` (or `1` or `yes`), or set the `Content-Type` header to `text/markdown`.
As of today, **Markdown is only supported in the web app.** Here's an example of how to enable Markdown formatting:

```
curl \
    -d "Look ma, **bold text**, *italics*, ..." \
    -H "Markdown: yes" \
    ntfy.sh/mytopic

ntfy publish \
    --markdown \
    mytopic \
    "Look ma, **bold text**, *italics*, ..."
```

## Scheduled delivery
You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself reminders or even to execute commands at a later date (if your subscriber acts on messages).

Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`, `X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`, `3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`, [and more](https://github.com/olebedev/when)). 

As of today, the minimum delay you can set is **10 seconds** and the maximum delay is **3 days**. This can be configured with the `message-delay-limit` option.

For the purposes of message caching, scheduled messages are kept in the cache until 12 hours after they were delivered (or whatever the server-side cache duration is set to). For instance, if a message is scheduled
to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally, turning off server-side caching is not possible in combination with this feature.  

```
curl -H "At: tomorrow, 10am" -d "Good morning" ntfy.sh/hello
curl -H "In: 30min" -d "It's 30 minutes later now" ntfy.sh/reminder
curl -H "Delay: 1639194738" -d "Unix timestamps are awesome" ntfy.sh/itsaunixsystem

ntfy publish \
    --at="tomorrow, 10am" \
    hello "Good morning"
```

Here are a few examples (assuming today's date is **12/10/2021, 9am, Eastern Time Zone**):

<table class="remove-md-box"><tr>
<td>
    <table><thead><tr><th><code>Delay/At/In</code> header</th><th>Message will be delivered at</th><th>Explanation</th></tr></thead><tbody>
    <tr><td><code>30m</code></td><td>12/10/2021, 9:<b>30</b>am</td><td>30 minutes from now</td></tr>
    <tr><td><code>2 hours</code></td><td>12/10/2021, <b>11:30</b>am</td><td>2 hours from now</td></tr>
    <tr><td><code>1 day</code></td><td>12/<b>11</b>/2021, 9am</td><td>24 hours from now</td></tr>
    <tr><td><code>10am</code></td><td>12/10/2021, <b>10am</b></td><td>Today at 10am (same day, because it's only 9am)</td></tr>
    <tr><td><code>8am</code></td><td>12/<b>11</b>/2021, <b>8am</b></td><td>Tomorrow at 8am (because it's 9am already)</td></tr>
    <tr><td><code>1639152000</code></td><td>12/10/2021, 11am (EST)</td><td> Today at 11am (EST)</td></tr>
    </tbody></table>
</td>
</tr></table>

## Webhooks (publish via GET)
In addition to using PUT/POST, you can also send to topics via simple HTTP GET requests. This makes it easy to use a ntfy topic as a [webhook](https://en.wikipedia.org/wiki/Webhook), or if your client has limited HTTP support.

To send messages via HTTP GET, simply call the `/publish` endpoint (or its aliases `/send` and `/trigger`). Without any arguments, this will send the message `triggered` to the topic. However, you can provide all arguments that are also supported as HTTP headers as URL-encoded arguments. Be sure to check the list of all supported parameters and headers for details.

For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhook/trigger` to send a message (aka trigger the webhook):

```
curl ntfy.sh/mywebhook/trigger

ntfy trigger mywebhook
```

To add a custom message, simply append the `message=` URL parameter. And of course you can set the [message priority](#message-priority), the [message title](#message-title), and [tags](#tags-emojis) as well. 
For a full list of possible parameters, check the list of [supported parameters and headers](#list-of-all-parameters).

Here's an example with a custom message, tags and a priority:

```
curl "ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull"

ntfy publish \
    -p 5 --tags=warning,skull \
    mywebhook "Webhook triggered"
```

## Message templating
Templating lets you **format a JSON message body into human-friendly message and title text** using [Go templates](https://pkg.go.dev/text/template) (see tutorials [here](https://blog.gopheracademy.com/advent-2017/using-go-templates/), [here](https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-go), and [here](https://developer.hashicorp.com/nomad/tutorials/templates/go-template-syntax)). This is specifically useful when **combined with webhooks** from services such as GitHub, Grafana, or other services that emit JSON webhooks.

Instead of using a separate bridge program to parse the webhook body into the format ntfy expects, you can include a templated message and/or a templated title which will be populated based on the fields of the webhook body (so long as the webhook body is valid JSON).

You can enable templating by setting the `X-Template` header (or its aliases `Template` or `tpl`) to `yes` or `1`, or (more appropriately for webhooks) by setting the `?template=yes` query parameter. Then, include templates in your `message` and/or `title`, using the following stanzas (see [Go docs](https://pkg.go.dev/text/template) for detailed syntax):

* Variables,, e.g. `{{.alert.title}}` or `An error occurred: {{.error.desc}}`
* Conditionals (if/else, e.g. `{{if eq .action "opened"}}..{{else}}..{{end}}`)
* Loops (e.g. `{{range .errors}}..{{end}}`)

> Info: Please note that the Go templating language is quite terrible. My apologies for using it for this feature. It is the best option for Go-based programs like ntfy. Stay calm and don't harm yourself or others in despair. **You can do it. I believe in you!**

## Publish as JSON
For some integrations with other tools, adding custom headers to HTTP requests may be tricky or impossible, so ntfy also allows publishing the entire message as JSON in the request body.

To publish as JSON, simple PUT/POST the JSON object directly to the ntfy root URL. The message format is described below the example.

Here's an example using most supported parameters. Check the table below for a complete list. The `topic` parameter is the only required one:

```
curl ntfy.sh \
    -d '{
    "topic": "mytopic",
    "message": "Disk space is low at 5.1 GB",
    "title": "Low disk space alert",
    "tags": ["warning","cd"],
    "priority": 4,
    "attach": "https://filesrv.lan/space.jpg",
    "filename": "diskspace.jpg",
    "click": "https://homecamera.lan/xasds1h2xsSsa/",
    "actions": [{ "action": "view", "label": "Admin panel", "url": "https://filesrv.lan/admin" }]
    }'
```

The JSON message format closely mirrors the format of the message you can consume when you subscribe via the API (see JSON message format for details), but is not exactly identical.
Here's an overview of all the supported fields:

| Field      | Required | Type                             | Example                                   | Description                                                           |
| ---------- | -------- | -------------------------------- | ----------------------------------------- | --------------------------------------------------------------------- |
| `topic`    | ✔️        | *string*                         | `topic1`                                  | Target topic name                                                     |
| `message`  | -        | *string*                         | `Some message`                            | Message body; set to `triggered` if empty or not passed               |
| `title`    | -        | *string*                         | `Some title`                              | Message title(#message-title)                                         |
| `tags`     | -        | *string array*                   | `["tag1","tag2"]`                         | List of [tags](#tags-emojis) that may or not map to emojis            |
| `priority` | -        | *int (one of: 1, 2, 3, 4, or 5)* | `4`                                       | Message [priority](#message-priority) with 1=min, 3=default and 5=max |
| `actions`  | -        | *JSON array*                     | *(see [action buttons](#action-buttons))* | Custom [user action buttons](#action-buttons) for notifications       |
| `click`    | -        | *URL*                            | `https://example.com`                     | Website opened when notification is [clicked](#click-action)          |
| `attach`   | -        | *URL*                            | `https://example.com/file.jpg`            | URL of an attachment, see [attach via URL](#attach-file-from-url)     |
| `markdown` | -        | *bool*                           | `true`                                    | Set to true if the `message` is Markdown-formatted                    |
| `icon`     | -        | *string*                         | `https://example.com/icon.png`            | URL to use as notification [icon](#icons)                             |
| `filename` | -        | *string*                         | `file.jpg`                                | File name of the attachment                                           |
| `delay`    | -        | *string*                         | `30min`, `9am`                            | Timestamp or duration for delayed delivery                            |
| `email`    | -        | *e-mail address*                 | `phil@example.com`                        | E-mail address for e-mail notifications                               |
| `call`     | -        | *phone number or 'yes'*          | `+1222334444` or `yes`                    | Phone number to use for [voice call](#phone-calls)                    |

## Action buttons
You can add action buttons to notifications to allow yourself to react to a notification directly. This is incredibly useful and has countless applications. 

You can control your home appliances (open/close garage door, change temperature on thermostat, ...), react to common monitoring alerts (clear logs when disk is full, ...), and many other things. The sky is the limit.

As of today, the following actions are supported:

* [`view`](#open-websiteapp): Opens a website or app when the action button is tapped
* [`broadcast`](#send-android-broadcast): Sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent when the action button is tapped (only supported on Android)
* [`http`](#send-http-request): Sends HTTP POST/GET/PUT request when the action button is tapped

### Defining actions
You can define **up to three user actions** in your notifications, using either of the following methods:

* In the [`X-Actions` header](#using-a-header), using a simple comma-separated format
* As a [JSON array](#using-a-json-array) in the `actions` key, when [publishing as JSON](#publish-as-json) 

#### Using a header
To define actions using the `X-Actions` header (or any of its aliases: `Actions`, `Action`), use the following format:

Header format (long)
```
action=<action1>, label=<label1>, paramN=... [; action=<action2>, label=<label2>, ...]
```

Header format (short)
```
<action1>, <label1>, paramN=... [; <action2>, <label2>, ...]
```

Multiple actions are separated by a semicolon (`;`), and key/value pairs are separated by commas (`,`). Values may be quoted with double quotes (`"`) or single quotes (`'`) if the value itself contains commas or semicolons. 

The `action=` and `label=` prefix are optional in all actions, and the `url=` prefix is optional in the `view` and `http` action. The only limitation of this format is that depending on your language/library, UTF-8 characters may not work. If they don't, use the [JSON array format](#using-a-json-array) instead.

As an example, here's how you can create the above notification using this format. Refer to the [`view` action](#open-websiteapp) and [`http` action](#send-http-request) section for details on the specific actions:

```
body='{"temperature": 65}'
curl \
    -d "You left the house. Turn down the A/C?" \
    -H "Actions: view, Open portal, https://home.nest.com/, clear=true; \
                    http, Turn down, https://api.nest.com/, body='$body'" \
    ntfy.sh/myhome

body='{"temperature": 65}'
ntfy publish \
    --actions="view, Open portal, https://home.nest.com/, clear=true; \
                http, Turn down, https://api.nest.com/, body='$body'" \
    myhome \
    "You left the house. Turn down the A/C?"
```

#### Using a JSON array
Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body (see publish as JSON):

```
curl ntfy.sh \
    -d '{
    "topic": "myhome",
    "message": "You left the house. Turn down the A/C?",
    "actions": [
        {
        "action": "view",
        "label": "Open portal",
        "url": "https://home.nest.com/",
        "clear": true
        },
        {
        "action": "http",
        "label": "Turn down",
        "url": "https://api.nest.com/",
        "body": "{\"temperature\": 65}"
        }
    ]
    }'

ntfy publish \
    --actions '[
        {
            "action": "view",
            "label": "Open portal",
            "url": "https://home.nest.com/",
            "clear": true
        },
        {
            "action": "http",
            "label": "Turn down",
            "url": "https://api.nest.com/",
            "body": "{\"temperature\": 65}"
        }
    ]' \
    myhome \
    "You left the house. Turn down the A/C?"
```

The required/optional fields for each action depend on the type of the action itself. Please refer to [`view` action](#open-websiteapp), [`broadcast` action](#send-android-broadcast), and [`http` action](#send-http-request) for details.

### Open website/app
The `view` action **opens a website or app when the action button is tapped**, e.g. a browser, a Google Maps location, or even a deep link into Twitter or a show ntfy topic. How exactly the action is handled depends on how Android and your desktop browser treat the links. Normally it'll just open a link in the browser. 

Examples:

* `http://` or `https://` will open your browser (or an app if it registered for a URL)
* `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
* `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
* `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
* `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
* ...

Here's an example using the [`X-Actions` header](#using-a-header):

```
curl \
    -d "Somebody retweeted your tweet." \
    -H "Actions: view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392" \
ntfy.sh/myhome

ntfy publish \
    --actions="view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392" \
    myhome \
    "Somebody retweeted your tweet."
```

And the same example using [JSON publishing](#publish-as-json):

```
curl ntfy.sh \
    -d '{
    "topic": "myhome",
    "message": "Somebody retweeted your tweet.",
    "actions": [
        {
        "action": "view",
        "label": "Open Twitter",
        "url": "https://twitter.com/binwiederhier/status/1467633927951163392"
        }
    ]
    }'

ntfy publish \
    --actions '[
        {
            "action": "view",
            "label": "Open Twitter",
            "url": "https://twitter.com/binwiederhier/status/1467633927951163392"
        }
    ]' \
    myhome \
    "Somebody retweeted your tweet."
```

The `view` action supports the following fields:

| Field    | Required | Type      | Default | Example               | Description                                      |
| -------- | -------- | --------- | ------- | --------------------- | ------------------------------------------------ |
| `action` | ✔️        | *string*  | -       | `view`                | Action type (**must be `view`**)                 |
| `label`  | ✔️        | *string*  | -       | `Turn on light`       | Label of the action button in the notification   |
| `url`    | ✔️        | *URL*     | -       | `https://example.com` | URL to open when action is tapped                |
| `clear`  | -️        | *boolean* | `false` | `true`                | Clear notification after action button is tapped |

### Send Android broadcast
The `broadcast` action **sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent when the action button is tapped**. This allows integration into automation apps such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), which basically means you can do everything your phone is capable of. Examples include taking pictures, launching/killing apps, change device settings, write/read files, etc.

By default, the intent action **`io.heckel.ntfy.USER_ACTION`** is broadcast, though this can be changed with the `intent` parameter (see below).
To send extras, use the `extras` parameter. Currently, **only string extras are supported**.

Here's an example using the [`X-Actions` header](#using-a-header):

```
curl \
    -d "Your wife requested you send a picture of yourself." \
    -H "Actions: broadcast, Take picture, extras.cmd=pic, extras.camera=front" \
ntfy.sh/wifey

ntfy publish \
    --actions="broadcast, Take picture, extras.cmd=pic, extras.camera=front" \
    wifey \
    "Your wife requested you send a picture of yourself."
```

And the same example using [JSON publishing](#publish-as-json):

```
curl ntfy.sh \
    -d '{
    "topic": "wifey",
    "message": "Your wife requested you send a picture of yourself.",
    "actions": [
        {
        "action": "broadcast",
        "label": "Take picture",
        "extras": {
            "cmd": "pic",
            "camera": "front"
        }
        }
    ]
    }'

ntfy publish \
    --actions '[
        {
            "action": "broadcast",
            "label": "Take picture",
            "extras": {
                "cmd": "pic",
                "camera": "front"
            }
        }
    ]' \
    wifey \
    "Your wife requested you send a picture of yourself."
```

The `broadcast` action supports the following fields:

| Field    | Required | Type             | Default                      | Example                 | Description                                                                                                                                                                            |
| -------- | -------- | ---------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action` | ✔️        | *string*         | -                            | `broadcast`             | Action type (**must be `broadcast`**)                                                                                                                                                  |
| `label`  | ✔️        | *string*         | -                            | `Turn on light`         | Label of the action button in the notification                                                                                                                                         |
| `intent` | -️        | *string*         | `io.heckel.ntfy.USER_ACTION` | `com.example.AN_INTENT` | Android intent name, **default is `io.heckel.ntfy.USER_ACTION`**                                                                                                                       |
| `extras` | -️        | *map of strings* | -                            | *see above*             | Android intent extras. Currently, only string extras are supported. When publishing as JSON, extras are passed as a map. When the simple format is used, use `extras.<param>=<value>`. |
| `clear`  | -️        | *boolean*        | `false`                      | `true`                  | Clear notification after action button is tapped                                                                                                                                       |

### Send HTTP request
The `http` action **sends a HTTP request when the action button is tapped**. You can use this to trigger REST APIs for whatever systems you have, e.g. opening the garage door, or turning on/off lights.

By default, this action sends a **POST request** (not GET!), though this can be changed with the `method` parameter. The only required parameter is `url`. Headers can be passed along using the `headers` parameter.  

Here's an example using the [`X-Actions` header](#using-a-header):

```
curl \
    -d "Garage door has been open for 15 minutes. Close it?" \
    -H "Actions: http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}" \
    ntfy.sh/myhome

ntfy publish \
    --actions="http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}" \
    myhome \
    "Garage door has been open for 15 minutes. Close it?"
```

And the same example using [JSON publishing](#publish-as-json):

```
curl ntfy.sh \
    -d '{
    "topic": "myhome",
    "message": "Garage door has been open for 15 minutes. Close it?",
    "actions": [
        {
        "action": "http",
        "label": "Close door",
        "url": "https://api.mygarage.lan/",
        "method": "PUT",
        "headers": {
            "Authorization": "Bearer zAzsx1sk.."
        },
        "body": "{\"action\": \"close\"}"
        }
    ]
    }'

ntfy publish \
    --actions '[
        {
            "action": "http",
            "label": "Close door",
            "url": "https://api.mygarage.lan/",
            "method": "PUT",
            "headers": {
            "Authorization": "Bearer zAzsx1sk.."
            },
            "body": "{\"action\": \"close\"}"
        }
    ]' \
    myhome \
    "Garage door has been open for 15 minutes. Close it?"
```

The `http` action supports the following fields:

| Field     | Required | Type               | Default  | Example                   | Description                                                                                                                                             |
| --------- | -------- | ------------------ | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`  | ✔️        | *string*           | -        | `http`                    | Action type (**must be `http`**)                                                                                                                        |
| `label`   | ✔️        | *string*           | -        | `Open garage door`        | Label of the action button in the notification                                                                                                          |
| `url`     | ✔️        | *string*           | -        | `https://ntfy.sh/mytopic` | URL to which the HTTP request will be sent                                                                                                              |
| `method`  | -️        | *GET/POST/PUT/...* | `POST` ⚠️ | `GET`                     | HTTP method to use for request, **default is POST** ⚠️                                                                                                   |
| `headers` | -️        | *map of strings*   | -        | *see above*               | HTTP headers to pass in request. When publishing as JSON, headers are passed as a map. When the simple format is used, use `headers.<header1>=<value>`. |
| `body`    | -️        | *string*           | *empty*  | `some body, somebody?`    | HTTP body                                                                                                                                               |
| `clear`   | -️        | *boolean*          | `false`  | `true`                    | Clear notification after HTTP request succeeds. If the request fails, the notification is not cleared.                                                  |

## Click action
You can define which URL to open when a notification is clicked. This may be useful if your notification is related to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open the web browser (or the app) and open the website.

To define a click action for the notification, pass a URL as the value of the `X-Click` header (or its alias `Click`).
If you pass a website URL (`http://` or `https://`) the web browser will open. If you pass another URI that can be handled by another app, the responsible app may open. 

Examples:

* `http://` or `https://` will open your browser (or an app if it registered for a URL)
* `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
* `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
* `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
* `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
* ...

Here's an example that will open Reddit when the notification is clicked:

```
curl \
    -d "New messages on Reddit" \
    -H "Click: https://www.reddit.com/message/messages" \
    ntfy.sh/reddit_alerts

ntfy publish \
    --click="https://www.reddit.com/message/messages" \
    reddit_alerts "New messages on Reddit"
```

## Attachments
You can **send images and other files to your phone** as attachments to a notification. The attachments are then downloaded onto your phone (depending on size and setting automatically), and can be used from the Downloads folder.

There are two different ways to send attachments: 

* sending [a local file](#attach-local-file) via PUT, e.g. from `~/Flowers/flower.jpg` or `ringtone.mp3`
* or by [passing an external URL](#attach-file-from-a-url) as an attachment, e.g. `https://f-droid.org/F-Droid.apk` 

### Attach local file
To **send a file from your computer** as an attachment, you can send it as the PUT request body. If a message is greater than the maximum message size (4,096 bytes) or consists of non UTF-8 characters, the ntfy server will automatically 
detect the mime type and size, and send the message as an attachment file. To send smaller text-only messages or files as attachments, you must pass a filename by passing the `X-Filename` header or query parameter (or any of its aliases `Filename`, `File` or `f`).

By default, and how ntfy.sh is configured, the **max attachment size is 15 MB** (with 100 MB total per visitor). 
Attachments **expire after 3 hours**, which typically is plenty of time for the user to download it, or for the Android app to auto-download it. Please also check out the [other limits below](#limitations).

Here's an example showing how to upload an image:

```
curl \
    -T flower.jpg \
    -H "Filename: flower.jpg" \
    ntfy.sh/flowers

ntfy publish \
    --file=flower.jpg \
    flowers
```

### Attach file from a URL
Instead of sending a local file to your phone, you can use **an external URL** to specify where the attachment is hosted.
This could be a Dropbox link, a file from social media, or any other publicly available URL. Since the files are externally hosted, the expiration or size limits from above do not apply here.

To attach an external file, simple pass the `X-Attach` header or query parameter (or any of its aliases `Attach` or `a`) to specify the attachment URL. It can be any type of file. 

ntfy will automatically try to derive the file name from the URL (e.g `https://example.com/flower.jpg` will yield a filename `flower.jpg`). To override this filename, you may send the `X-Filename` header or query parameter (or any of its aliases `Filename`, `File` or `f`).

Here's an example showing how to attach an APK file:

```
curl \
    -X POST \
    -H "Attach: https://f-droid.org/F-Droid.apk" \
    ntfy.sh/mydownloads

ntfy publish \
    --attach="https://f-droid.org/F-Droid.apk" \
    mydownloads
```

## Icons
You can include an icon that will appear next to the text of the notification. Simply pass the `X-Icon` header or query parameter (or its alias `Icon`) to specify the URL that the icon is located at. The client will automatically download the icon (unless it is already cached locally, and less than 24 hours old), and show it in the notification. Icons are cached locally in the client until the notification is deleted. **Only JPEG and PNG images are supported at this time**.

Here's an example showing how to include an icon:

```
curl \
    -H "Icon: https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png" \
    -H "Title: Kodi: Resuming Playback" \
    -H "Tags: arrow_forward" \
    -d "The Wire, S01E01" \
    ntfy.sh/tvshows

ntfy publish \
    --icon="https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png" \
    --title="Kodi: Resuming Playback" \
    --tags="arrow_forward" \
    tvshows \
    "The Wire, S01E01"
```

## Compose

```yml
services:
  ntfy:
    image: binwiederhier/ntfy
    container_name: ntfy
    command:
      - serve
    environment:
      - TZ=UTC    # optional: set desired timezone
    user: UID:GID # optional: replace with your own user/group or uid/gid
    volumes:
      - /var/cache/ntfy:/var/cache/ntfy
      - /etc/ntfy:/etc/ntfy
    ports:
      - 80:80
    healthcheck: # optional: remember to adapt the host:port to your environment
        test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1"]
        interval: 60s
        timeout: 10s
        retries: 3
        start_period: 40s
    restart: unless-stopped
```
