From appfolio-pack
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".
npx claudepluginhub flight505/skill-forge --plugin appfolio-packThis skill is limited to using the following tools:
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.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
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.
# 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
// 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 };
# 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.