Skip to content

Fetch

RouterOS /tool/fetch transfers files and makes HTTP/HTTPS requests from the router itself. It supports downloading files from remote servers, uploading files (including config backups), and calling REST APIs from scripts. All four protocols are supported: HTTP, HTTPS, FTP, and SFTP.

/tool fetch
ParameterDefaultDescription
urlFull URL including protocol, host, path, and optional query string
mode(from URL)Override protocol: http, https, ftp, sftp
http-methodgetHTTP method: get, post, put, delete, patch
http-dataRequest body payload for POST/PUT (max 64 KB)
http-header-fieldCustom HTTP headers as Name: Value pairs, comma-separated
http-content-encodingCompress payload before sending: gzip or deflate
http-max-redirect-countMaximum number of HTTP redirects to follow
http-outputdataHTTP-specific output handling: data or none
http-user-agentOverride the User-Agent header
outputfileWhere to place the response: file, user, user-with-headers, print, none
dst-pathLocal filename to write response (for output=file)
src-pathLocal file to upload (for upload=yes)
uploadnoyes to upload src-path to the remote URL
userUsername for FTP/SFTP authentication
passwordPassword for FTP/SFTP authentication
asciinoFTP only: use ASCII transfer mode instead of binary
host-keySFTP server host key for server identity verification
check-certificatenoHTTPS certificate validation: no, yes, yes-without-crl
certificateName of a certificate in the RouterOS store to use for client auth
as-valueFlag: return fetch result as a record (for script variable capture)
ModeBehavior
fileWrite response body to local file (dst-path) — default
userStore response body in script variable (max 64 KB)
user-with-headersStore headers + body in variable; body effectively capped at ~20 KB
printPrint response body to terminal
noneDiscard response
# Download a file
/tool fetch url="https://example.com/config.rsc" dst-path="config.rsc"

Use output=user and as-value to capture the response in a script:

:local result [/tool fetch url="https://api.ipify.org/" output=user as-value]
:put ($result->"data")

Separate multiple headers with commas. If a header value contains a literal comma, escape it as \,:

/tool fetch url="https://api.example.com/status" \
http-header-field="Authorization: Bearer mytoken,Accept: application/json" \
output=user

Include query parameters directly in the URL:

/tool fetch url="https://api.example.com/query?type=full&format=json" output=print

Set http-method=post and supply the request body in http-data. The Content-Type header must be set explicitly when sending structured payloads.

/tool fetch url="https://api.example.com/events" \
http-method=post \
http-data="{\"router\":\"core1\",\"status\":\"up\"}" \
http-header-field="Content-Type: application/json" \
output=user
/tool fetch url="https://notify.example.com/alert" \
http-method=post \
http-data="host=core1&event=reboot" \
http-header-field="Content-Type: application/x-www-form-urlencoded"

RouterOS scripts can send event-driven alerts to any HTTP webhook endpoint — including Slack, Teams, PagerDuty, or custom monitoring systems — using a JSON POST.

:local identity [/system identity get name]
:local payload ("{\"text\":\"Router alert: WAN down on " . $identity . "\"}")
/tool fetch url="https://hooks.example.com/services/T000/B000/xxxx" \
http-method=post \
http-data=$payload \
http-header-field="Content-Type: application/json" \
output=none

Pair /tool fetch with Netwatch to fire a webhook whenever a host goes down or comes back up:

# Store the notifier as a named script
/system script add name="notify-down" source={
/tool fetch url="https://hooks.example.com/services/T000/B000/xxxx" \
http-method=post \
http-data="{\"text\":\"8.8.8.8 is DOWN\"}" \
http-header-field="Content-Type: application/json" \
output=none
}
/system script add name="notify-up" source={
/tool fetch url="https://hooks.example.com/services/T000/B000/xxxx" \
http-method=post \
http-data="{\"text\":\"8.8.8.8 is UP\"}" \
http-header-field="Content-Type: application/json" \
output=none
}
# Create the Netwatch probe
/tool netwatch add host=8.8.8.8 interval=30s \
down-script="/system script run notify-down" \
up-script="/system script run notify-up"

Send a periodic status ping to confirm the router is reachable:

/system script add name="heartbeat" source={
:local t [/system clock get time]
:local identity [/system identity get name]
:local payload ("{\"text\":\"[" . $identity . "] heartbeat at " . $t . "\"}")
/tool fetch url="https://hooks.example.com/services/T000/B000/xxxx" \
http-method=post \
http-data=$payload \
http-header-field="Content-Type: application/json" \
output=none
}
/system scheduler add name="heartbeat" interval=5m on-event="heartbeat" \
policy=read,write,test

Credentials can be embedded in the URL or passed as separate user= and password= parameters.

/tool fetch url="ftp://192.0.2.10/backups/router.backup" \
user="ftpuser" password="ftppass" \
dst-path="router.backup"
/tool fetch url="ftp://192.0.2.10/incoming/router.backup" \
user="ftpuser" password="ftppass" \
upload=yes src-path="router.backup"

Use ascii=no (the default) for binary files such as .backup archives. Use ascii=yes only for plain text files when the remote server requires ASCII mode.

SFTP uses the same upload/src-path/dst-path conventions as FTP. For security, pin the server’s host key with host-key=.

/tool fetch url="sftp://198.51.100.20/home/backup/router.backup" \
user="sftpuser" password="sftppass" \
dst-path="router.backup"
/tool fetch url="sftp://198.51.100.20/upload/router.backup" \
user="sftpuser" password="sftppass" \
upload=yes src-path="router.backup" \
host-key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..."

Omitting host-key= skips server identity verification — acceptable in trusted networks, but avoid it over untrusted links.

By default, /tool/fetch does not validate TLS certificates (check-certificate=no). Enable validation for production use.

ValueBehaviour
noNo certificate validation (default)
yesValidate chain and CRL
yes-without-crlValidate chain, skip CRL check

Use yes-without-crl when the CA’s CRL endpoint is unreachable from the router.

Before check-certificate=yes will work, import the issuing CA into the RouterOS certificate store and mark it trusted:

/certificate import file-name=ca.pem
/certificate set [find where name~"ca"] trusted=yes
/tool fetch url="https://example.com/file.txt" \
check-certificate=yes \
dst-path="file.txt"

If certificate validation fails, ensure:

  1. The system clock is set correctly (/system clock print)
  2. The CA certificate and any intermediates are imported
  3. Each CA certificate has trusted=yes

A common pattern is to generate a config export or binary backup and upload it to a remote server. Run this as a scheduled script for automated daily backups.

# Automated backup + SFTP upload
:local id [/system identity get name]
:local d [/system clock get date]
:local t [/system clock get time]
# Build a datestamp string: YYYY-MM-DD_HH-MM-SS
:local ds ([:pick $d 7 11] . "-" . [:pick $d 0 3] . "-" . [:pick $d 4 6])
:local ts ([:pick $t 0 2] . "-" . [:pick $t 3 5] . "-" . [:pick $t 6 8])
:local fn ($id . "_" . $ds . "_" . $ts)
# Generate text export
/export terse show-sensitive file=($fn . ".rsc")
# Generate binary backup
/system backup save name=$fn
:delay 3
# Upload both files
/tool fetch url=("sftp://198.51.100.20/backups/" . $fn . ".rsc") \
upload=yes src-path=($fn . ".rsc") \
user="backupuser" password="backuppass"
/tool fetch url=("sftp://198.51.100.20/backups/" . $fn . ".backup") \
upload=yes src-path=($fn . ".backup") \
user="backupuser" password="backuppass"
/system scheduler add \
name="daily-backup-upload" \
start-time=03:00:00 \
interval=1d \
on-event="/system script run backup-upload" \
policy=read,write,ftp,password,sensitive

Store the backup script body in /system script with name backup-upload.

Download a .npk package from your own update mirror and install it on next reboot:

:local pkg "routeros-arm64-7.16.2.npk"
/tool fetch url=("https://updates.example.net/ros/" . $pkg) \
dst-path=$pkg \
check-certificate=yes
/system reboot

Fetch from a private artifact store using a Bearer token:

/tool fetch url="https://artifacts.example.net/api/v1/files/job.rsc" \
http-header-field="Authorization: Bearer <TOKEN>" \
check-certificate=yes \
dst-path="job.rsc"
/tool fetch url="https://example.com/scripts/watchdog.rsc" \
check-certificate=yes dst-path="watchdog.rsc"
/import file-name=watchdog.rsc

Inspect downloaded script files before importing them. Verify the source and check the file contents with /file print or Winbox file browser.

Use output=user with as-value to read a small JSON or text response into a variable:

:local r [/tool fetch url="https://api.example.com/device/status" \
http-header-field="Authorization: Bearer <TOKEN>" \
output=user as-value]
:local body ($r->"data")
:log info ("API response: " . $body)

The user output mode accepts up to 64 KB. Use user-with-headers to also capture HTTP response headers (body then limited to ~20 KB).

Automated Config Update from Central Server

Section titled “Automated Config Update from Central Server”

Pull a configuration script from a central server on a schedule and apply it:

/system script add name="apply-config-update" source={
/tool fetch url="https://config.example.net/routers/core1.rsc" \
check-certificate=yes \
dst-path="update.rsc"
# Verify file was downloaded before importing
:if ([:len [/file find name="update.rsc"]] > 0) do={
/import file-name=update.rsc
/file remove "update.rsc"
}
}
/system scheduler add name="config-sync" start-time=02:00:00 interval=1d \
on-event="/system script run apply-config-update" \
policy=read,write,ftp,policy,password,sensitive

Always inspect scripts before importing. Download to a test environment first and review the file contents with /file print or the Winbox file browser.

SymptomLikely CauseFix
TLS handshake failedCertificate not trusted or clock wrongCheck system time; import and trust CA
no such item on as-valueFetch failed silentlyAdd output=print temporarily to see error
Upload writes empty filesrc-path file does not existVerify with /file print before running fetch
FTP returns permission deniedIncorrect credentials or pathVerify user=, password=, and remote path
SFTP host key mismatchServer key changedUpdate host-key= to new server key