SureCart Demos – Bulk Delete Webhooks

Tech Articles | August 22, 2025 | Automation, Blog, Coding, Plugins, SureCart, Wordpress

I generate a lot of demo stores up till today I thought there was infact no limit to the number of websites you could connect to SureCart after all i’ve been doing it for months, well it turns out there is a limit I hit it for the first time today.

Image

The magic number is 50 one you have 50 webhooks it wont let you add anymore so by that reasoning you have a 50 useable limit for connected stores. Now I don’t think anyone is going to have 50 connected stores but it happened here due to demo stores.

Now I don’t want to delete all those stores by hand (95% of them are dead and gone) the others I can manually reconnect quicker.

So i looked at the API and it turns out even webhooks are in the API scope so i set about writing a little bash script to clear them out in a jiffy. This script should be 100% portable too so it will work on Windows (git bash in my case) macOS and Linux

#!/usr/bin/env sh
# Portable (POSIX sh) script to list and delete all SureCart webhook endpoints.
# Works on Linux, macOS, and Windows Git Bash/MSYS/Cygwin.

# How to USE
# export SURECART_API_KEY="sc_xxx"
# chmod +x clear-surecart-webhooks.sh

# # See what would be deleted (default dry-run):
# ./clear-surecart-webhooks.sh

# # Actually delete:
# ./clear-surecart-webhooks.sh --yes

# # Quiet:
# ./clear-surecart-webhooks.sh --yes --silent



set -eu

API_BASE="https://api.surecart.com/v1"
API_KEY="${SURECART_API_KEY:-}"
DRY_RUN=1
SILENT=0
LIMIT=100

usage() {
  cat <<'EOF'
Usage: clear-surecart-webhooks.sh [--yes] [--silent] [-h|--help]

Deletes ALL SureCart webhook endpoints in your account.

Environment:
  SURECART_API_KEY   Your SureCart API key (required)

Flags:
  --yes              Perform deletions (without this it's a dry run)
  --silent           Less output
  -h|--help          Show this help
EOF
}

# --- parse args (POSIX) ---
while [ "${1-}" ]; do
  case "$1" in
    --yes) DRY_RUN=0 ;;
    --silent) SILENT=1 ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown argument: $1" >&2; usage; exit 1 ;;
  esac
  shift
done

# --- checks ---
[ -n "$API_KEY" ] || { echo "Error: SURECART_API_KEY is not set." >&2; exit 1; }
command -v jq >/dev/null 2>&1 || { echo "Error: 'jq' is required." >&2; exit 1; }
command -v curl >/dev/null 2>&1 || { echo "Error: 'curl' is required." >&2; exit 1; }

# --- headers ---
HDR_AUTH="Authorization: Bearer ${API_KEY}"
HDR_ACCEPT="Accept: application/json"
HDR_CT="Content-Type: application/json"

# --- temp file and cleanup ---
IDS_FILE="$(mktemp 2>/dev/null || echo "/tmp/clear-surecart-webhooks.$$")"
cleanup() { rm -f "$IDS_FILE"; }
trap cleanup EXIT HUP INT TERM

# --- paginate + collect IDs safely ---
PAGE=1
while : ; do
  RESP="$(curl -sS -H "$HDR_AUTH" -H "$HDR_CT" -H "$HDR_ACCEPT" \
    -- "${API_BASE}/webhook_endpoints?limit=${LIMIT}&page=${PAGE}")" || {
      echo "Error: request failed on page ${PAGE}." >&2; exit 1; }

  # Validate JSON
  echo "$RESP" | jq -e . >/dev/null 2>&1 || {
    echo "Error: non-JSON response on page ${PAGE}." >&2; exit 1; }

  # Extract IDs; strip any CRs to be Windows-safe
  PAGE_COUNT="$(printf '%s' "$RESP" | jq '[.data[]?.id] | length')"
  if [ "${PAGE_COUNT:-0}" -eq 0 ]; then
    break
  fi

  printf '%s' "$RESP" | jq -r '.data[]?.id // empty' | tr -d '\r' >> "$IDS_FILE"
  PAGE=$((PAGE + 1))
done

TOTAL="$(wc -l < "$IDS_FILE" | tr -d '[:space:]')"
[ "${TOTAL:-0}" -gt 0 ] || { [ "$SILENT" -eq 1 ] || echo "Found 0 webhook endpoint(s)."; exit 0; }
[ "$SILENT" -eq 1 ] || echo "Found ${TOTAL} webhook endpoint(s)."

# --- dry run ---
if [ "$DRY_RUN" -eq 1 ]; then
  if [ "$SILENT" -eq 0 ]; then
    echo "Dry run: would delete the following IDs:"
    sed 's/^/  - /' "$IDS_FILE"
    echo "Run again with --yes to actually delete."
  else
    cat "$IDS_FILE"
  fi
  exit 0
fi

# --- destructive phase ---
ERRORS=0
# Read line-by-line, preserving text and stripping CR/LF defensively
# (avoid IFS tricks to keep IDs exact)
while IFS= read -r RAW_ID || [ -n "$RAW_ID" ]; do
  ID_CLEAN="$(printf '%s' "$RAW_ID" | tr -d '\r\n')"
  [ "$SILENT" -eq 1 ] || echo "Deleting webhook endpoint: ${ID_CLEAN}"

  # First attempt
  HTTP_CODE="$(curl -sS -o /dev/null -w '%{http_code}' \
    -H "$HDR_AUTH" -H "$HDR_CT" -H "$HDR_ACCEPT" -X DELETE \
    -- "${API_BASE}/webhook_endpoints/${ID_CLEAN}")" || HTTP_CODE="000"

  if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "204" ]; then
    [ "$SILENT" -eq 1 ] || echo "  -> deleted"
    continue
  fi

  if [ "$HTTP_CODE" = "429" ]; then
    [ "$SILENT" -eq 1 ] || echo "  -> rate-limited; sleeping 2s and retrying…"
    sleep 2
    HTTP_CODE2="$(curl -sS -o /dev/null -w '%{http_code}' \
      -H "$HDR_AUTH" -H "$HDR_CT" -H "$HDR_ACCEPT" -X DELETE \
      -- "${API_BASE}/webhook_endpoints/${ID_CLEAN}")" || HTTP_CODE2="000"
    if [ "$HTTP_CODE2" = "200" ] || [ "$HTTP_CODE2" = "204" ]; then
      [ "$SILENT" -eq 1 ] || echo "  -> deleted (after retry)"
    else
      echo "  -> failed with HTTP ${HTTP_CODE2}" >&2
      ERRORS=$((ERRORS + 1))
    fi
  else
    echo "  -> failed with HTTP ${HTTP_CODE}" >&2
    ERRORS=$((ERRORS + 1))
  fi
done < "$IDS_FILE"

if [ "$ERRORS" -gt 0 ]; then
  echo "Completed with ${ERRORS} error(s)." >&2
  exit 1
fi

[ "$SILENT" -eq 1 ] || echo "All webhook endpoints deleted."
PHP

With the above script I was able to clear them out in seconds and now I don’t need to delete my store and remake all my products for my demos and demo videos.

That to me is a win win situation.

Support the Author

buy me a coffee
Really Useful Plugin Logo
Wpvideobank temp
Appoligies for any spelling and grammer issue. As a dyslexic i need to rely on tools for this they like me are not perfect but I do try my best