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           
      Provide an API endpoint that returns data in the required JSON format. Data will be fetched and updated automatically.
{
"mirrors": {
"mirror1": "...",
"mirror2": "...",
...
"mirror20": "...",
"signature1": "...",
"signature2": "...",
...
"signature20": "...",
}
}
        
          β’ 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.