Claude-code-plugins-plus-skills appfolio-debug-bundle
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/appfolio-pack/skills/appfolio-debug-bundle" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-appfolio-debug-bundle && rm -rf "$T"
manifest:
plugins/saas-packs/appfolio-pack/skills/appfolio-debug-bundle/SKILL.mdsource content
AppFolio Debug Bundle
Overview
This debug bundle collects diagnostic evidence from AppFolio property management API integrations for support escalation and root cause analysis. It captures API connectivity against the properties, tenants, and work orders endpoints, authentication status using client credential pairs, recent error logs from integration pipelines, and SDK version information. The resulting tarball gives support engineers everything they need to diagnose connectivity failures, auth rejections, and data sync issues without requiring live access to your environment.
Prerequisites
,curl
,jq
installedtar
andAPPFOLIO_CLIENT_ID
configured (basic auth pair)APPFOLIO_CLIENT_SECRET
set to your Stack API base (e.g.,APPFOLIO_BASE_URL
)https://yourcompany.appfolio.com/api/v1
Debug Collection Script
#!/bin/bash set -euo pipefail BUNDLE="debug-appfolio-$(date +%Y%m%d-%H%M%S)" mkdir -p "$BUNDLE" # Environment check echo "=== Environment ===" > "$BUNDLE/environment.txt" echo "Base URL: ${APPFOLIO_BASE_URL:-NOT SET}" >> "$BUNDLE/environment.txt" echo "Client ID: ${APPFOLIO_CLIENT_ID:+SET (redacted)}" >> "$BUNDLE/environment.txt" echo "Client Secret: ${APPFOLIO_CLIENT_SECRET:+SET (redacted)}" >> "$BUNDLE/environment.txt" echo "Node: $(node -v 2>/dev/null || echo 'not installed')" >> "$BUNDLE/environment.txt" echo "Timestamp: $(date -u)" >> "$BUNDLE/environment.txt" # API connectivity — properties endpoint echo "=== API Health ===" > "$BUNDLE/api-health.txt" curl -sf -o "$BUNDLE/api-health.txt" -w "HTTP %{http_code} in %{time_total}s\n" \ -u "${APPFOLIO_CLIENT_ID}:${APPFOLIO_CLIENT_SECRET}" \ "${APPFOLIO_BASE_URL}/properties?per_page=1" 2>&1 || echo "UNREACHABLE" > "$BUNDLE/api-health.txt" # Work orders endpoint probe echo "=== Work Orders ===" > "$BUNDLE/work-orders.txt" curl -sf -w "HTTP %{http_code}\n" \ -u "${APPFOLIO_CLIENT_ID}:${APPFOLIO_CLIENT_SECRET}" \ "${APPFOLIO_BASE_URL}/work_orders?per_page=1" >> "$BUNDLE/work-orders.txt" 2>&1 || echo "FAILED" >> "$BUNDLE/work-orders.txt" # Tenant endpoint probe echo "=== Tenants ===" > "$BUNDLE/tenants.txt" curl -sf -w "HTTP %{http_code}\n" \ -u "${APPFOLIO_CLIENT_ID}:${APPFOLIO_CLIENT_SECRET}" \ "${APPFOLIO_BASE_URL}/tenants?per_page=1" >> "$BUNDLE/tenants.txt" 2>&1 || echo "FAILED" >> "$BUNDLE/tenants.txt" # Recent integration logs echo "=== Recent Logs ===" > "$BUNDLE/app-logs.txt" tail -100 /var/log/appfolio-sync/*.log >> "$BUNDLE/app-logs.txt" 2>/dev/null || echo "No sync logs found" >> "$BUNDLE/app-logs.txt" # Rate limit headers echo "=== Rate Limits ===" > "$BUNDLE/rate-limits.txt" curl -sI -u "${APPFOLIO_CLIENT_ID}:${APPFOLIO_CLIENT_SECRET}" \ "${APPFOLIO_BASE_URL}/properties?per_page=1" 2>/dev/null | grep -i "x-rate\|retry-after\|x-ratelimit" >> "$BUNDLE/rate-limits.txt" || echo "No rate limit headers" >> "$BUNDLE/rate-limits.txt" # Package versions echo "=== Dependencies ===" > "$BUNDLE/deps.txt" npm ls 2>/dev/null | grep -i appfolio >> "$BUNDLE/deps.txt" || echo "No AppFolio npm packages found" >> "$BUNDLE/deps.txt" tar -czf "$BUNDLE.tar.gz" "$BUNDLE" && rm -rf "$BUNDLE" echo "Bundle: $BUNDLE.tar.gz"
Analyzing the Bundle
tar -xzf debug-appfolio-*.tar.gz cat debug-appfolio-*/environment.txt # Verify credentials are set cat debug-appfolio-*/api-health.txt # Check HTTP status and latency cat debug-appfolio-*/rate-limits.txt # Confirm not throttled jq '.errors' debug-appfolio-*/work-orders.txt 2>/dev/null # Parse error payloads
Common Issues
| Symptom | Check in Bundle | Fix |
|---|---|---|
| 401 on all endpoints | shows client ID/secret NOT SET | Set and in env |
| 403 Forbidden on tenants | HTTP 403 | Stack API scope missing; request tenant read permission in AppFolio partner portal |
| 429 Too Many Requests | shows retry-after header | Back off and implement exponential retry; AppFolio allows 120 req/min |
| Timeout on work orders | shows time > 30s | Reduce parameter; filter by to narrow result set |
| Empty property list | returns | Verify points to correct portfolio; check property group filters |
| SSL certificate error | shows curl SSL error | Update CA bundle: ; check proxy settings |
Automated Health Check
async function checkAppFolioHealth(): Promise<{ status: string; latencyMs: number; endpoints: Record<string, number>; }> { const baseUrl = process.env.APPFOLIO_BASE_URL; const creds = Buffer.from( `${process.env.APPFOLIO_CLIENT_ID}:${process.env.APPFOLIO_CLIENT_SECRET}` ).toString("base64"); const headers = { Authorization: `Basic ${creds}` }; const endpoints = ["properties", "tenants", "work_orders"]; const results: Record<string, number> = {}; const start = Date.now(); for (const ep of endpoints) { const res = await fetch(`${baseUrl}/${ep}?per_page=1`, { headers }); results[ep] = res.status; } return { status: Object.values(results).every((s) => s === 200) ? "healthy" : "degraded", latencyMs: Date.now() - start, endpoints: results, }; }
Resources
Next Steps
See
appfolio-rate-limits.