Skip to content

Port scanning (discovery)

Port scanning (port discovery) answers the question “which TCP ports are open on this host at all?”. Notifly goes through the ports of a profile or of a given range, tries to connect to each of them and collects a list of open ports. Unlike the port monitor, which continuously watches a known set of ports, a scan is a one-time (or periodic) inventory: you don’t yet know what is listening on the host and want to find out.

Typical flow: you start a scan → look at the discovered ports → with one request turn the result into a continuous port monitor, which will alert if any of these ports suddenly closes.

create a scan task → status=pending
└─▶ the Notifly scanner (runs once a minute) picks up the task,
resolves the host to an IP (resolvedIP) → status=running
└─▶ on each pass it checks the next portion of ports:
a TCP connection with a per-port timeout timeoutSec,
open ports are added to foundPorts (CSV) right away
└─▶ no ports left → status=completed, report to channel appid
  • The scan runs from the Notifly cloud, so the host must be reachable from the internet. The scanner does not probe private, loopback or link-local addresses (10.x, 192.168.x, 127.0.0.1, 169.254.x, etc.) — connections to them are blocked, and such a scan completes with no open ports.
  • Speed depends on whether ownership of the host is verified: for a verified host a pass checks up to 350 ports (16 parallel connections), for an unverified one up to 50 (6 connections). Roughly, with a free queue: quick takes about 1–2 minutes, standard about 4 minutes verified and 20+ minutes unverified, full about 3 hours verified and about a day unverified.
  • cursor is how many ports have been processed; the admin UI shows progress based on it. foundPorts is accumulated live — partial results are visible before the scan completes.
  • During a long scan the channel receives progress notifications (around 25, 50 and 75 %, priority 0), and on completion a report (see below).
  • A user cannot have two active scans of the same host (409). If the same host is being scanned right now by another task, the new one waits in pending; if there is a completed scan of this host no older than 5 minutes, its result is reused immediately (lastError will read shared from recent scan).

What to scan is set by the profile (profile):

profileWhat it scansPorts
quicknmap top-100 — the most common TCP ports99
standardports 1–1024 + 59 popular ports above 10241083
fullthe entire range 1–6553565535
customyour rangeFrom–rangeTo (default 1–65535)you decide

For quick, standard and full the server fills in the ports itself and ignores the range you pass. In the response, rangeFrom/rangeTo of preset profiles are 1…the number of ports in the profile, not port numbers.

  • appid — the channel that receives the report (required): your own or shared with send permission.
  • name — task name, 1–200 characters (required).
  • host — host name or IP (required), without / and spaces.
  • profile — quick / standard / full / custom, see above.
  • rangeFrom / rangeTo — range bounds for custom, each in [1, 65535], rangeFrom ≤ rangeTo. Defaults are 1 and 65535.
  • timeoutSec — per-port connection timeout, default 2, maximum 10.
  • repeatIntervalSec — 0 = one-time scan; > 0 = repeat every N seconds after completion, minimum 3600 (1 hour). See Recurring scan.
  • alertTitle / alertMessage / alertMessageMarkdown / alertPriority — report formatting; alertPriority in [0, 10].

When the scan completes, a message is sent to channel appid:

  • title — alertTitle, or, if it is empty, a default “scan completed” title with the host name;
  • text — your alertMessage (if set) as a prefix, followed by a summary: the host and its IP, how many ports were scanned, the duration, the number of open ports and their list (the first 50, then “and N more”);
  • priority — alertPriority; with alertMessageMarkdown: true the message is rendered as Markdown.

With repeatIntervalSec > 0 the task does not stay completed after it finishes: the report is sent, the found ports move to prevFoundPorts, and the task returns to pending with a start in repeatIntervalSec seconds. So between runs a recurring scan has an empty foundPorts, and the result of the last run is in prevFoundPorts; the admin UI uses it to compare with the previous scan (which ports appeared and which closed).

To stop repeating, call POST /port-scan/:id/cancel or PATCH with "repeatIntervalSec": 0 (then the next run will be the last one).

Scans use a separate daily tariff limit, portScansPerDay (they are not part of the dailyEvents quota). The limit counts units, not tasks: one unit is each processed portion of ports, each progress notification and the final report.

PlanUnits per day
Free10
Pro300
Business10000

Approximate cost of one scan:

ProfileHost verifiedHost not verified
quick~2~4
standard~8several dozen
full~190more than 1300

So Free fits a few quick scans a day, while a full scan is realistic only for a verified host on Pro or Business.

If the counter is already exhausted, creating a scan returns 429 (daily scan limit reached). If the limit runs out in the middle of a scan, the task ends with status failed and lastError: "quota exceeded", and you receive a quota notification. The counter is reset once a day together with the other daily quotas — see Quotas and tariffs.

  1. Open app.notifly.ru → Monitors → the Ports tab → the Discovery sub-tab.
  2. Click “Scan host”, fill in the name and host, choose a profile (Quick, Standard, Full or Custom range), repetition, channel and, optionally, the report message prefix. The per-port timeout in the creation dialog is 2 seconds.
  3. Start it — progress and found ports update in the list. The “Details” button shows the open ports, duration and a comparison with the previous scan.

You can also start a scan of a host that already has a port monitor right from the monitor’s row — with the “Scan all ports on this host (Discovery)” button.

Окно терминала
# Quick scan (top-100 ports), one-time
curl -X POST "$NOTIFLY_URL/port-scan" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{
"appid": 12345,
"name": "Prod host inventory",
"host": "prod.example.com",
"profile": "quick",
"timeoutSec": 2,
"alertTitle": "Scan completed",
"alertMessage": "Open ports found on prod.example.com",
"alertPriority": 5
}'
Окно терминала
# Custom range, repeat daily
curl -X POST "$NOTIFLY_URL/port-scan" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{
"appid": 12345,
"name": "Ports 8000–9000 on the app host",
"host": "app.example.com",
"profile": "custom",
"rangeFrom": 8000,
"rangeTo": 9000,
"timeoutSec": 3,
"repeatIntervalSec": 86400,
"alertMessage": "Range 8000–9000 on app.example.com has been scanned"
}'

The response is 201 with the created scan object: status: "pending", cursor: 0, an empty foundPorts and the assigned id. Errors come as {"error": "..."}.

Окно терминала
# List all scan tasks
curl "$NOTIFLY_URL/port-scan" -H "X-Notifly-Key: <api-token>"
# One scan — progress and found ports
curl "$NOTIFLY_URL/port-scan/777" -H "X-Notifly-Key: <api-token>"

In the response look at status (pending → running → completed/failed/cancelled), cursor (how many ports have been processed), foundPorts (CSV of open ports), prevFoundPorts (the result of the previous run), resolvedIP, startedAt, completedAt. On failed the reason is in lastError (for example, a host resolution error or quota exceeded).

Окно терминала
# Cancel an unfinished scan
curl -X POST "$NOTIFLY_URL/port-scan/777/cancel" \
-H "X-Notifly-Key: <api-token>"
# Restart a completed/cancelled/failed scan
curl -X POST "$NOTIFLY_URL/port-scan/777/restart" \
-H "X-Notifly-Key: <api-token>"
  • Cancel moves the scan to cancelled; for a scan that is already completed/cancelled it returns 400.
  • Restart is available for a scan that is not active: the previous foundPorts moves to prevFoundPorts, progress is reset and the scan starts over. If the scan is still pending/running — 400 (cancel it first); if another of your scans of this host is already active — 409.
  • Edit — PATCH /port-scan/:id with any subset of the fields appid, name, host, rangeFrom, rangeTo, timeoutSec (1–10), repeatIntervalSec, alertTitle, alertMessage, alertMessageMarkdown, alertPriority. The profile cannot be changed. While the scan is running, editing is not allowed (400); changes take effect from the next start of the scan.

A completed scan can be turned into a continuous port monitor with one request. The found ports (foundPorts) become the expectedPorts of a new monitor in closed mode — it will alert if any of the discovered ports closes.

Окно терминала
curl -X POST "$NOTIFLY_URL/port-scan/777/to-monitor" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <api-token>" \
-d '{
"name": "prod.example.com ports",
"intervalSec": 300,
"timeoutSec": 5,
"alertTitle": "Port alert: prod.example.com",
"alertMessage": "An expected port closed on prod.example.com",
"alertPriority": 7
}'

The request body is optional — the fields have defaults: name = Monitor <host>, intervalSec = 300, timeoutSec = 5, alertTitle = Port alert: <host>, alertMessage = Port closed on <host>, alertPriority = 0. The monitor inherits the scan’s appid and host and is created without a recovery message — you can add one later via PUT /port-monitor/:id. The response is 201 with the monitor object.

Restrictions:

  • The scan must be completed (otherwise 400). A recurring scan does not stay in this status — disable repetition first and wait for the next run.
  • The scan must have found open ports — an empty foundPorts gives 400.
  • The server rejects duplicate monitors for a host with 409, but for now it only catches a monitor that has not yet passed its first check — check the list of port monitors before creating one.

Authorization is the X-Notifly-Key header with an API token. Channel tokens and share tokens are not accepted on these endpoints (403).

MethodPathDescription
GET/port-scanList of the user’s scan tasks
GET/port-scan/:idOne scan: status, progress (cursor), foundPorts
POST/port-scanCreate a scan (201; 429 — daily limit or the 24-hour full-scan cooldown; 409 — you already scan this host)
PATCH/port-scan/:idChange settings (not allowed for a running scan)
DELETE/port-scan/:idDelete a scan task
POST/port-scan/:id/cancelCancel an unfinished scan
POST/port-scan/:id/restartRestart an inactive scan
POST/port-scan/:id/to-monitorCreate a port monitor from the found ports