All requests must include an
Authorization
header with your API key.
Use your fixed API key provided by TOR.WATCH Include it in every request header.
Authorization: your_api_key_here
Method | Endpoint | Description |
---|---|---|
GET | /api/v2/mirrors | List all mirrors |
GET | /api/v2/mirrors/{id} | Retrieve a specific mirror |
POST | /api/v2/mirrors | Create a new mirror |
PUT | /api/v2/mirrors/{id} | Update an existing mirror |
DELETE | /api/v2/mirrors/{id} | Delete a mirror |
Retrieve all available mirrors.
GET {baseURL}/api/v2/mirrors
curl -X GET "{baseURL}/api/v2/mirrors" \
-H "Authorization: your_api_key_here"
Retrieve details for a specific mirror by ID.
GET {baseURL}/api/v2/mirrors/{id}
curl -X GET "{baseURL}/api/v2/mirrors/95" \
-H "Authorization: your_api_key_here"
Add a new mirror record to the system.
POST {baseURL}/api/v2/mirrors
{
"url": "http://glich.com",
"signature": "mysig",
"captcha": true
}
curl -X POST "{baseURL}/api/v2/mirrors" \
-H "Authorization: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "http://glich.com",
"signature": "mysig",
"captcha": true
}'
Modify an existing mirror record by ID.
PUT {baseURL}/api/v2/mirrors/{id}
{
"url": "http://1111.com",
"signature": "111111",
"captcha": true
}
curl -X PUT "{baseURL}/api/v2/mirrors/88" \
-H "Authorization: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "http://1111.com",
"signature": "111111",
"captcha": true
}'
Remove a mirror record by ID.
DELETE {baseURL}/api/v2/mirrors/{id}
curl -X DELETE "{baseURL}/api/v2/mirrors/95" \
-H "Authorization: your_api_key_here"
A fully featured bash
terminal
utility to interact with the TOR.WATCH API v2.
Requirements: curl jq
Command | Description |
---|---|
./tdw_api.sh list | Show all mirrors (basic info) |
./tdw_api.sh list full | Show all mirrors with full details |
./tdw_api.sh list csv | Show all mirrors formatted as CSV |
./tdw_api.sh show 95 | Retrieve mirror #95 |
./tdw_api.sh create "http://mirror.onion" "signature" true | Create a new mirror entry |
./tdw_api.sh update 88 "http://mirror11.com" "-" true | Update mirror #88 |
./tdw_api.sh delete 95 | Delete mirror #95 |
./tdw_api.sh delete-multiple 1,2,3,..,95 | Delete multiple mirrors by IDs |
./tdw_api.sh delete-all | Delete all mirrors β |
./tdw_api.sh create-multiple mirrors.csv | Bulk create mirrors from CSV |
./tdw_api.sh update-multiple mirrors-update.csv | Bulk update mirrors from CSV |
To view all options with examples, run:
./tdw_api.sh help
βοΈ Configuration Required
Ensure that both the BASE_URL and
API_KEY are properly set in the
tdw_api.sh
# --- CONFIGURATION ---
#!/bin/bash
# ===============================================================
# TOR.WATCH API v2 Terminal Client
# ===============================================================
# Usage examples:
# ./tdw_api.sh list
# ./tdw_api.sh list full
# ./tdw_api.sh list csv
# ./tdw_api.sh show 95
# ./tdw_api.sh create "http://mirror.onion" "signature" true
# ./tdw_api.sh update 88 "http://mirror11.com" "-" true
# ./tdw_api.sh delete 95
# ./tdw_api.sh delete-multiple 1,2,3
# ./tdw_api.sh delete-all
# ./tdw_api.sh create-multiple mirrors.csv
# ./tdw_api.sh update-multiple mirrors-update.csv
# ===============================================================
# --- CONFIGURATION ---
BASE_URL="api_base_url"
API_KEY="your_api_key_here"
# --- COLORS & ICONS ---
GREEN='\033[0;32m'
CYAN='\033[0;36m'
RED='\033[0;31m'
GRAY='\033[0;90m'
YELLOW='\033[1;33m'
NC='\033[0m'
OK_ICON="β
"
FAIL_ICON="β"
# --- DEPENDENCY CHECKS ---
check_dependencies() {
missing=0
if ! command -v curl &> /dev/null; then
echo -e "${RED}Error:${NC} curl is required but not installed."
echo -e "${YELLOW}Install curl with one of the following:${NC}"
echo " Ubuntu/Debian: sudo apt install curl"
echo " Fedora: sudo dnf install curl"
echo " Arch Linux: sudo pacman -S curl"
echo " macOS (Homebrew): brew install curl"
missing=1
fi
if command -v jq &> /dev/null; then
PARSER="jq"
else
PARSER="cat"
echo -e "${YELLOW}Note:${NC} jq not found. Pretty-printing disabled for single requests."
echo -e "${GRAY}Bulk operations (create-multiple, update-multiple, delete-all) require jq. Install jq to use them.${NC}"
fi
if [ $missing -eq 1 ]; then
exit 1
fi
}
ensure_jq_for_bulk() {
if [ "$PARSER" != "jq" ]; then
echo -e "${RED}Error:${NC} This operation requires 'jq'."
echo "Install jq and re-run. Example:"
echo " Ubuntu/Debian: sudo apt install jq"
echo " macOS (Homebrew): brew install jq"
exit 1
fi
}
# --- HEADER ---
print_header() {
echo -e "${CYAN}ββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
echo -e "${GREEN} TOR.WATCH API v2 Terminal Client${NC}"
echo -e "${CYAN}ββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
}
# --- HTTP helper ---
# Usage: http_call METHOD URL [DATA_JSON]
# Sets global LAST_HTTP_CODE and prints body (pretty if jq available)
http_call() {
local method=$1 url=$2 data="$3"
local resp http_code body
if [ -n "$data" ]; then
resp=$(curl -sS -w "\n%{http_code}" -X "$method" "$url" \
-H "Authorization: ${API_KEY}" \
-H "Content-Type: application/json" \
-d "$data")
else
resp=$(curl -sS -w "\n%{http_code}" -X "$method" "$url" \
-H "Authorization: ${API_KEY}")
fi
http_code=$(echo "$resp" | tail -n1)
body=$(echo "$resp" | sed '$d')
LAST_HTTP_CODE=$http_code
if [ -n "$body" ]; then
if [ "$PARSER" = "jq" ]; then
echo "$body" | jq .
else
echo "$body"
fi
fi
return 0
}
# --- UTIL ---
trim() { printf '%s' "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'; }
# --- COMMANDS ---
# list: summary or full
# list: summary or full
list_mirrors() {
# fetch
resp=$(curl -sS -H "Authorization: ${API_KEY}" "${BASE_URL}/api/v2/mirrors")
if [ -z "$resp" ]; then
echo -e "${RED}Error:${NC} Failed to fetch mirrors."
return 1
fi
# normalize to array
if [ "$PARSER" = "jq" ]; then
# extract an array into variable
arr_json=$(echo "$resp" | jq -c 'if type=="object" and has("mirrors") then .mirrors elif type=="array" then . else [] end')
if [ "$1" = "full" ]; then
# Output full JSON
echo "$arr_json" | jq .
return 0
elif [ "$1" = "csv" ]; then
# Output CSV format for easy export
echo "id,url,signature,captcha"
echo "$arr_json" | jq -r '.[] | "\(.ID // .id),\(.url // .URL),\(.signature // ""),\(.captcha // false)"'
return 0
fi
# print summary table (default)
printf "%-8s %-48s %-20s %-6s\n" "ID" "URL" "SIGNATURE" "CAP"
printf "%-8s %-48s %-20s %-6s\n" "--------" "------------------------------------------------" "--------------------" "------"
# extract fields and print nicely
echo "$arr_json" | jq -r '.[] | [(.ID // .id // "null"), (.url // .URL // ""), (.signature // ""), (.captcha // false)] | @tsv' |
while IFS=$'\t' read -r id url signature captcha; do
id=$(trim "$id")
url=$(trim "$url")
signature=$(trim "$signature")
captcha=$(trim "$captcha")
printf "%-8s %-48s %-20s %-6s\n" "$id" "$url" "$signature" "$captcha"
done
else
# no jq: print raw
echo "$resp"
fi
}
show_mirror() {
id=$1
[ -z "$id" ] && { echo -e "${RED}Error:${NC} Missing mirror ID"; exit 1; }
http_call GET "${BASE_URL}/api/v2/mirrors/${id}"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} OK (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
}
create_mirror() {
url=$1
signature=$2
captcha=$3
if [ -z "$url" ]; then
echo -e "${RED}Error:${NC} create requires and (signature optional)."
echo "Usage: ./tdw_api.sh create [signature] "
exit 1
fi
if [ -z "$captcha" ]; then
echo -e "${RED}Error:${NC} captcha is required (true|false)."
exit 1
fi
if [ "$captcha" != "true" ] && [ "$captcha" != "false" ]; then
echo -e "${RED}Error:${NC} captcha must be 'true' or 'false'."
exit 1
fi
# β
Default signature if empty
if [ -z "$signature" ]; then
signature="-"
fi
# Build JSON payload cleanly
data=$(jq -n --arg url "$url" --arg sig "$signature" --argjson cap $captcha \
'{url:$url, signature:$sig, captcha:$cap}')
echo -e "${GRAY}β Payload:${NC} $data"
http_call POST "${BASE_URL}/api/v2/mirrors" "$data"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Created (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
}
update_mirror() {
id=$1
url=$2
signature=$3
captcha=$4
if [ -z "$id" ] || [ -z "$url" ]; then
echo -e "${RED}Error:${NC} update requires (signature optional)."
echo "Usage: ./tdw_api.sh update "
exit 1
fi
if [ -z "$captcha" ]; then
echo -e "${RED}Error:${NC} captcha is required (true|false)."
exit 1
fi
if [ "$captcha" != "true" ] && [ "$captcha" != "false" ]; then
echo -e "${RED}Error:${NC} captcha must be 'true' or 'false'."
exit 1
fi
signature=${signature:-""}
data=$(jq -n --arg url "$url" --arg sig "$signature" --argjson cap $captcha '{url:$url, signature:$sig, captcha:$cap}')
http_call PUT "${BASE_URL}/api/v2/mirrors/${id}" "$data"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Updated (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
}
delete_mirror() {
id=$1
[ -z "$id" ] && { echo -e "${RED}Error:${NC} Missing mirror ID"; exit 1; }
http_call DELETE "${BASE_URL}/api/v2/mirrors/${id}"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Deleted (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
}
delete_multiple_mirrors() {
ids=$1
if [ -z "$ids" ]; then
echo -e "${RED}Usage:${NC} ./tdw_api.sh delete-multiple "
exit 1
fi
ensure_jq_for_bulk
IFS=',' read -ra arr <<< "$ids"
for id in "${arr[@]}"; do
id=$(trim "$id")
echo -e "${GRAY}Deleting mirror ID: ${id}${NC}"
http_call DELETE "${BASE_URL}/api/v2/mirrors/${id}"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Deleted (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
echo
done
}
delete_all_mirrors() {
ensure_jq_for_bulk
echo -e "${YELLOW}β οΈ WARNING: This will delete ALL mirrors.${NC}"
read -p "Type YES to confirm: " confirm
if [ "$confirm" != "YES" ]; then
echo "Canceled."
exit 0
fi
echo -e "${GRAY}Fetching mirrors...${NC}"
json=$(curl -sS -H "Authorization: ${API_KEY}" "${BASE_URL}/api/v2/mirrors")
ids=$(echo "$json" | jq -r '
if type=="array" then .[] | ( .ID // .id // empty )
elif type=="object" and has("mirrors") then .mirrors[] | ( .ID // .id // empty )
else empty end
')
if [ -z "$ids" ]; then
echo "No mirrors found (or failed to retrieve)."
exit 0
fi
for id in $ids; do
id=$(trim "$id")
echo -e "${GRAY}Deleting mirror ID: ${id}${NC}"
http_call DELETE "${BASE_URL}/api/v2/mirrors/${id}"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Deleted (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
echo
done
}
# create-multiple expects CSV: url,signature,captcha
create_multiple_mirrors() {
file=$1
if [ -z "$file" ]; then
echo -e "${RED}Usage:${NC} ./tdw_api.sh create-multiple "
exit 1
fi
ensure_jq_for_bulk
if [ ! -f "$file" ]; then
echo -e "${RED}Error:${NC} File not found: $file"
exit 1
fi
echo -e "${CYAN}Preview from $file:${NC}"
nl -ba -w3 -s' ' "$file" | sed -n '1,10p'
echo
read -p "Type YES to proceed with creation of entries from this CSV: " confirm
if [ "$confirm" != "YES" ]; then echo "Canceled."; exit 0; fi
while IFS=',' read -r url signature captcha || [ -n "$url" ]; do
url=$(trim "$url")
signature=$(trim "$signature")
captcha=$(trim "$captcha")
if echo "$url" | grep -iq '^url$'; then continue; fi
if [ -z "$url" ]; then
echo -e "${YELLOW}Skipping empty URL line${NC}"
continue
fi
if [ -z "$captcha" ]; then
echo -e "${RED}Error:${NC} captcha is required for each entry (true|false). Skipping $url"
continue
fi
if [ "$captcha" != "true" ] && [ "$captcha" != "false" ]; then
echo -e "${RED}Error:${NC} captcha must be 'true' or 'false' for $url. Skipping."
continue
fi
signature=${signature:-""}
echo -e "${GRAY}Creating: ${url} (captcha=${captcha})${NC}"
data=$(jq -n --arg url "$url" --arg sig "$signature" --argjson cap $captcha '{url:$url, signature:$sig, captcha:$cap}')
http_call POST "${BASE_URL}/api/v2/mirrors" "$data"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Created (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
echo
done < "$file"
}
# update-multiple expects CSV: id,url,signature,captcha
update_multiple_mirrors() {
file=$1
if [ -z "$file" ]; then
echo -e "${RED}Usage:${NC} ./tdw_api.sh update-multiple "
exit 1
fi
ensure_jq_for_bulk
if [ ! -f "$file" ]; then
echo -e "${RED}Error:${NC} File not found: $file"
exit 1
fi
echo -e "${CYAN}Preview from $file:${NC}"
nl -ba -w3 -s' ' "$file" | sed -n '1,10p'
echo
read -p "Type YES to proceed with updates from this CSV: " confirm
if [ "$confirm" != "YES" ]; then echo "Canceled."; exit 0; fi
while IFS=',' read -r id url signature captcha || [ -n "$id" ]; do
id=$(trim "$id")
url=$(trim "$url")
signature=$(trim "$signature")
captcha=$(trim "$captcha")
if echo "$id" | grep -iq '^id$'; then continue; fi
if [ -z "$id" ] || [ -z "$url" ]; then
echo -e "${YELLOW}Skipping invalid line: id or url missing${NC}"
continue
fi
if [ -z "$captcha" ]; then
echo -e "${RED}Error:${NC} captcha is required for each entry (true|false). Skipping id ${id}"
continue
fi
if [ "$captcha" != "true" ] && [ "$captcha" != "false" ]; then
echo -e "${RED}Error:${NC} captcha must be 'true' or 'false' for id ${id}. Skipping."
continue
fi
signature=${signature:-""}
echo -e "${GRAY}Updating ID ${id}: ${url} (captcha=${captcha})${NC}"
data=$(jq -n --arg url "$url" --arg sig "$signature" --argjson cap $captcha '{url:$url, signature:$sig, captcha:$cap}')
http_call PUT "${BASE_URL}/api/v2/mirrors/${id}" "$data"
code=$LAST_HTTP_CODE
if [ "$code" -ge 200 ] && [ "$code" -lt 300 ]; then
echo -e "${GREEN}${OK_ICON} Updated (${code})${NC}"
else
echo -e "${RED}${FAIL_ICON} HTTP ${code}${NC}"
fi
echo
done < "$file"
}
# --- HELP MENU ---
show_help() {
echo -e "${YELLOW}Usage:${NC}"
echo -e " ${GREEN}./tdw_api.sh${NC} ${BLUE}${NC} [options]\n"
echo -e "${YELLOW}Commands:${NC}"
echo -e " ${GREEN}list${NC} [full|csv] Show all mirrors (summary, full JSON, or CSV)"
echo -e " ${GREEN}show${NC} ID Show details of a specific mirror"
echo -e " ${GREEN}create${NC} "
echo -e " ${GREEN}update${NC} "
echo -e " ${GREEN}delete${NC} ID Delete a mirror by ID"
echo -e " ${GREEN}delete-multiple${NC} ID,ID Delete multiple mirrors at once"
echo -e " ${GREEN}delete-all${NC} β οΈ Delete ALL mirrors (with confirmation)"
echo -e " ${GREEN}create-multiple${NC} mirrors.csv Create multiple mirrors from CSV"
echo -e " ${GREEN}update-multiple${NC} mirrors.csv Update multiple mirrors from CSV\n"
echo -e "${YELLOW}CSV formats:${NC}"
echo -e " ${GREEN}create-multiple:${NC} ${GRAY}url,signature,captcha${NC}"
echo -e " e.g.: ${BLUE}http://a.com,abc123,true${NC}"
echo -e " ${GREEN}update-multiple:${NC} ${GRAY}id,url,signature,captcha${NC}"
echo -e " e.g.: ${BLUE}88,http://x.com,newSig,true${NC}\n"
echo -e "${RED}If Error: β HTTP${NC} ${code} β validation failed."
echo -e "${YELLOW}β οΈ Tip:${NC} Check your BASE_URL, API_KEY, and Signature values. The signature field cannot be empty \"\" use \"-\" if you donβt have one."
}
# --- MAIN ---
check_dependencies
print_header
case "$1" in
list) list_mirrors "$2" ;;
show) show_mirror "$2" ;;
create) create_mirror "$2" "$3" "$4" ;;
update) update_mirror "$2" "$3" "$4" "$5" ;;
delete) delete_mirror "$2" ;;
delete-multiple) delete_multiple_mirrors "$2" ;;
delete-all) delete_all_mirrors ;;
create-multiple) create_multiple_mirrors "$2" ;;
update-multiple) update_multiple_mirrors "$2" ;;
help|--help|-h|"") show_help ;;
*) echo -e "${RED}Unknown command:${NC} $1"; show_help ;;
esac
β’ The JSON structure and key names must remain exactly as shown.
β’ Supports up to 20 mirror and signature pairs (signatures optional but recommended).
β’ CAPTCHA protection applies automatically starting from mirror2; mirror1 remains unprotected.