TOR.WATCH API v2 Documentation

All requests must include an Authorization header with your API key.

πŸ’‘ A fully featured Bash terminal client is available

Authentication

Use your fixed API key provided by TOR.WATCH Include it in every request header.

Authorization: your_api_key_here

Endpoints Overview

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

List Mirrors

Retrieve all available mirrors.

GET {baseURL}/api/v2/mirrors

Example cURL

curl -X GET "{baseURL}/api/v2/mirrors" \
-H "Authorization: your_api_key_here"

Show Mirror

Retrieve details for a specific mirror by ID.

GET {baseURL}/api/v2/mirrors/{id}

Example cURL

curl -X GET "{baseURL}/api/v2/mirrors/95" \
-H "Authorization: your_api_key_here"

Create Mirror

Add a new mirror record to the system.

POST {baseURL}/api/v2/mirrors

Request Body

{
  "url": "http://glich.com",
  "signature": "mysig",
  "captcha": true
}

Example cURL

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
}'

Update Mirror

Modify an existing mirror record by ID.

PUT {baseURL}/api/v2/mirrors/{id}

Request Body

{
  "url": "http://1111.com",
  "signature": "111111",
  "captcha": true
}

Example cURL

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
}'

Delete Mirror

Remove a mirror record by ID.

DELETE {baseURL}/api/v2/mirrors/{id}

Example cURL

curl -X DELETE "{baseURL}/api/v2/mirrors/95" \
-H "Authorization: your_api_key_here"

πŸ’» Terminal Client

A fully featured bash terminal utility to interact with the TOR.WATCH API v2.

  • View, create, update, and delete mirrors directly from your terminal
  • Supports bulk CSV import, update and delete
Requirements: curl jq

Available Commands

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 ---

πŸ”½ Show tdw_api.sh Script
#!/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.