#!/usr/bin/env bash # Auth + discovery probe for Qonto + Wise. Run this once after dropping # fresh tokens into .env. It confirms auth works and prints the IDs you # need (Qonto bank account ids, Wise business profile id + balance ids). # # Usage: # bank-probe.sh # # Token values are NEVER printed. Only metadata + slugs / ids are. # Output is safe to commit as an examples/ baseline. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BANK_CURL="${SCRIPT_DIR}/bank-curl.sh" set -a; source "${SCRIPT_DIR}/../../dolibarr/.env"; set +a # A redactor that masks anything that looks like a token / secret / key # in case the API ever echoes credentials back to us. Defense in depth. redact() { python3 - <<'PY' import sys, re s = sys.stdin.read() # Mask long alphanumeric runs (typical tokens) and any explicit "token"/"secret"/"key" values s = re.sub(r'([A-Fa-f0-9]{32,})', '', s) s = re.sub(r'([A-Za-z0-9_-]{40,})', '', s) s = re.sub(r'("(?:token|secret|key|password)"\s*:\s*")[^"]*(")', r'\1\2', s, flags=re.IGNORECASE) print(s, end='') PY } echo "================================================================================" echo " bank-probe — auth + discovery" echo "================================================================================" echo # ---------------------------- Qonto ---------------------------- echo "--- QONTO ---" echo " base : https://thirdparty.qonto.com" echo " auth shape : Authorization: :" echo " env vars : QONTO_LOGIN=${QONTO_LOGIN:+} QONTO_SECRET_KEY=${QONTO_SECRET_KEY:+} QONTO_ORG_SLUG=${QONTO_ORG_SLUG:-}" echo if QONTO_ORG_RAW="$("${BANK_CURL}" qonto /v2/organization 2>&1)"; then python3 - </dev/null || true # Robust version: write to tmp file, parse from there (avoids quoting hell) TMP_QONTO=$(mktemp -t qonto.XXXXXX.json) trap 'rm -f "${TMP_QONTO}"' EXIT if "${BANK_CURL}" qonto /v2/organization > "${TMP_QONTO}"; then python3 - "${TMP_QONTO}" <<'PY' import json, sys d = json.load(open(sys.argv[1])) org = d.get("organization") or {} print(f" [OK] auth succeeded") print(f" slug : {org.get('slug')}") print(f" legal_name : {org.get('legal_name')}") print(f" legal_country : {org.get('legal_country')}") accs = org.get("bank_accounts") or [] print(f" {len(accs)} bank account(s):") for a in accs: iban = a.get("iban") or "" iban_tail = iban[-8:] if iban else "-" print(f" id={a.get('id')} name={a.get('name','-')} ...iban={iban_tail} status={a.get('status','-')} balance={a.get('balance','-')} {a.get('balance_cents_currency','')}") PY else echo " [XX] Qonto auth FAILED — check QONTO_LOGIN / QONTO_SECRET_KEY in .env" fi echo # ---------------------------- Wise ---------------------------- echo "--- WISE ---" echo " base : https://api.wise.com" echo " auth shape : Authorization: Bearer " echo " env vars : WISE_API_TOKEN=${WISE_API_TOKEN:+} WISE_PROFILE_ID=${WISE_PROFILE_ID:-}" echo TMP_WISE_PROFILES=$(mktemp -t wise.XXXXXX.json) trap 'rm -f "${TMP_QONTO}" "${TMP_WISE_PROFILES}"' EXIT if "${BANK_CURL}" wise /v2/profiles > "${TMP_WISE_PROFILES}"; then python3 - "${TMP_WISE_PROFILES}" "${WISE_PROFILE_ID:-}" <<'PY' import json, sys profiles = json.load(open(sys.argv[1])) env_pid = sys.argv[2] print(f" [OK] auth succeeded") print(f" {len(profiles)} profile(s):") business_pid = None for p in profiles: name = p.get("fullName") or p.get("businessName") or (p.get("details") or {}).get("name", "-") marker = "" if str(p.get("id")) == env_pid: marker = " ← .env WISE_PROFILE_ID" if p.get("type") == "BUSINESS" and not business_pid: business_pid = p.get("id") print(f" id={p.get('id')} type={p.get('type','-'):<10} name={name}{marker}") if env_pid and business_pid and str(business_pid) != env_pid: print(f" [!!] WISE_PROFILE_ID in .env ({env_pid}) is NOT the BUSINESS profile ({business_pid}).") print(f" Use the BUSINESS one for Arcodange.") elif not env_pid and business_pid: print(f" [→] Set WISE_PROFILE_ID={business_pid} in .env (BUSINESS profile).") PY else echo " [XX] Wise auth FAILED — check WISE_API_TOKEN in .env" fi echo # Wise balances + balance ids (needed for /balance-statements queries) if [[ -n "${WISE_PROFILE_ID:-}" ]]; then echo "--- WISE balances (for the BUSINESS profile) ---" TMP_WISE_BAL=$(mktemp -t wisebal.XXXXXX.json) trap 'rm -f "${TMP_QONTO}" "${TMP_WISE_PROFILES}" "${TMP_WISE_BAL}"' EXIT if "${BANK_CURL}" wise "/v4/profiles/${WISE_PROFILE_ID}/balances?types=STANDARD" > "${TMP_WISE_BAL}"; then python3 - "${TMP_WISE_BAL}" <<'PY' import json, sys bal = json.load(open(sys.argv[1])) print(f" {len(bal)} balance(s):") for b in bal: amt = (b.get('amount') or {}).get('value', '?') cur = (b.get('amount') or {}).get('currency', '?') print(f" id={b.get('id')} type={b.get('type','-'):<8} currency={cur:<3} balance={amt} {cur} name={b.get('name','-')}") PY else echo " [XX] /balances fetch failed — token may not have balances scope, or profile id is wrong." fi fi echo echo "--- summary ---" echo " .env should ultimately contain:" echo " QONTO_LOGIN=" echo " QONTO_SECRET_KEY=" echo " QONTO_ORG_SLUG=$(grep -E '^QONTO_ORG_SLUG' "${SCRIPT_DIR}/../../dolibarr/.env" | cut -d= -f2 || echo '')" echo " WISE_API_TOKEN=" echo " WISE_PROFILE_ID="