Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure AppFolio Stack API authentication with OAuth 2.0. Use when setting up property management API access, registering as an AppFolio Stack partner, or configuring client credentials for API calls. Trigger: "install appfolio", "setup appfolio", "appfolio auth", "appfolio API key".
.claude/skills/jeremylongshore-appfolio-install-auth/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 5% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 57% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 91% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 31% | 0% |
Configure AppFolio Stack API authentication. AppFolio uses HTTP Basic Auth with a client ID and client secret, provided through their Stack partner program. No public npm SDK exists — use direct REST API calls.
bash# AppFolio Stack API credentials come from the partner program # 1. Apply at appfolio.com/stack/become-a-partner # 2. Complete integration review # 3. Receive client_id and client_secret cat > .env << 'ENVFILE' APPFOLIO_CLIENT_ID=your-client-id APPFOLIO_CLIENT_SECRET=your-client-secret APPFOLIO_BASE_URL=https://your-company.appfolio.com/api/v1 ENVFILE chmod 600 .env echo ".env" >> .gitignore
typescript// src/appfolio-client.ts import axios, { AxiosInstance } from 'axios'; class AppFolioClient { private api: AxiosInstance; constructor() { this.api = axios.create({ baseURL: process.env.APPFOLIO_BASE_URL, auth: { username: process.env.APPFOLIO_CLIENT_ID!, password: process.env.APPFOLIO_CLIENT_SECRET!, }, headers: { 'Content-Type': 'application/json' }, timeout: 30000, }); } async verifyConnection(): Promise<boolean> { try { const response = await this.api.get('/properties'); console.log(`Connected! Found ${response.data.length} properties`); return true; } catch (error: any) { console.error(`Connection failed: ${error.response?.status} ${error.message}`); return false; } } get http(): AxiosInstance { return this.api; } } export { AppFolioClient };
bash# Quick curl test curl -u "${APPFOLIO_CLIENT_ID}:${APPFOLIO_CLIENT_SECRET}" \ "${APPFOLIO_BASE_URL}/properties" | jq '.[0]'
| Resource | Endpoint | Methods | |----------|----------|---------| | Properties | /api/v1/properties | GET | | Units | /api/v1/units | GET | | Tenants | /api/v1/tenants | GET | | Leases | /api/v1/leases | GET, POST | | Bills | /api/v1/bills | GET, POST | | Vendors | /api/v1/vendors | GET | | Owners | /api/v1/owners | GET | | Reports | /api/v1/reports | GET |
.env| Error | Cause | Solution | |-------|-------|----------| | 401 Unauthorized | Invalid credentials | Verify client_id/secret from AppFolio | | 403 Forbidden | Not a Stack partner | Complete partner application | | 404 Not Found | Wrong base URL | Use your-company.appfolio.com format | | Timeout | Network issue | Check firewall allows HTTPS to appfolio.com |
Proceed to appfolio-hello-world for your first property query.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 13,981 | 10,847 | -22% | 1 | 1 | 0% | 3,210 | 3,293 | +3% | 0 | 0 | — |
case-02 | fail→pass | 12,143 | 8,033 | -34% | 1 | 1 | 0% | 2,684 | 2,813 | +5% | 0 | 0 | — |
case-03 | fail→fail | 7,351 | 4,748 | -35% | 1 | 1 | 0% | 1,456 | 1,945 | +34% | 0 | 0 | — |
case-04 | pass→pass | 11,110 | 5,360 | -52% | 1 | 1 | 0% | 1,779 | 1,964 | +10% | 0 | 0 | — |
case-05 | fail→pass | 5,336 | 2,568 | -52% | 1 | 1 | 0% | 867 | 1,358 | +57% | 0 | 0 | — |
case-06 | pass→pass | 8,035 | 5,132 | -36% | 1 | 1 | 0% | 1,391 | 1,901 | +37% | 0 | 0 | — |
case-07 | pass→pass | 7,294 | 3,573 | -51% | 1 | 1 | 0% | 1,342 | 1,511 | +13% | 0 | 0 | — |
case-08 | pass→pass | 9,722 | 6,334 | -35% | 1 | 1 | 0% | 1,836 | 2,096 | +14% | 0 | 0 | — |
case-09 | pass→pass | 4,084 | 2,889 | -29% | 1 | 1 | 0% | 698 | 1,397 | +100% | 0 | 0 | — |
case-10 | pass→pass | 9,743 | 4,666 | -52% | 1 | 1 | 0% | 1,705 | 1,851 | +9% | 0 | 0 | — |
case-11 | fail→pass | 8,330 | 2,999 | -64% | 1 | 1 | 0% | 1,411 | 1,464 | +4% | 0 | 0 | — |
case-12 | pass→pass | 10,079 | 6,768 | -33% | 1 | 1 | 0% | 1,771 | 2,147 | +21% | 0 | 0 | — |
case-13 | pass→pass | 4,204 | 2,494 | -41% | 1 | 1 | 0% | 737 | 1,246 | +69% | 0 | 0 | — |
case-14 | pass→pass | 6,677 | 4,095 | -39% | 1 | 1 | 0% | 1,157 | 1,767 | +53% | 0 | 0 | — |
case-15 | pass→pass | 5,797 | 1,590 | -73% | 1 | 1 | 0% | 1,018 | 1,249 | +23% | 0 | 0 | — |
case-16 | fail→pass | 6,962 | 5,459 | -22% | 1 | 1 | 0% | 842 | 1,612 | +91% | 0 | 0 | — |
case-17 | pass→pass | 5,146 | 2,466 | -52% | 1 | 1 | 0% | 862 | 1,356 | +57% | 0 | 0 | — |
case-18 | pass→pass | 6,611 | 1,658 | -75% | 1 | 1 | 0% | 1,098 | 1,261 | +15% | 0 | 0 | — |
case-19 | fail→pass | 5,409 | 2,102 | -61% | 1 | 1 | 0% | 937 | 1,231 | +31% | 0 | 0 | — |
case-20 | pass→pass | 4,124 | 3,491 | -15% | 1 | 1 | 0% | 693 | 1,527 | +120% | 0 | 0 | — |
case-21 | fail→pass | 14,212 | 11,533 | -19% | 1 | 1 | 0% | 2,484 | 3,322 | +34% | 0 | 0 | — |
case-22 | pass→pass | 10,936 | 10,235 | -6% | 1 | 1 | 0% | 1,799 | 2,962 | +65% | 0 | 0 | — |
case-23 | fail→fail | 11,550 | 13,237 | +15% | 1 | 1 | 0% | 2,350 | 3,588 | +53% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +26 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.