Build integrations with the Perch API. Access properties, transactions, bookings, and reports programmatically.
The Perch API lets you read and write rental property data — properties, transactions, bookings, categorization rules, participation hours, and reports. It's a standard REST API with JSON payloads and API key authentication.
Log into app.getperch.ai, click API in the nav bar, and generate a key. API access requires a Starter plan ($29/mo) or higher.
Two key types:
pk_user_...) — access your own datapk_cpa_...) — access all clients who have shared with youcurl -H "Authorization: Bearer pk_user_YOUR_KEY" \
https://api.getperch.ai/v1/properties
All API requests require an API key in the Authorization header:
Authorization: Bearer pk_user_your-api-key-here
Keys are scoped to the user who generated them. CPA keys (pk_cpa_...) can access all shared client accounts by passing ?owner_uid=CLIENT_UID on requests.
API keys are shown once on creation. Store them securely — we only store the SHA-256 hash.
Base URL: https://api.getperch.ai/api/v1
CRUD for rental properties — name, address, type, listing channels.
Create, categorize, and query financial transactions. Filter by property, date, category.
Guest bookings with channel, revenue, and date data.
Auto-categorization rules for transaction patterns.
Log material participation hours for IRS compliance.
Portfolio summary and financial reports (read-only).
All responses return JSON. List endpoints include pagination metadata:
{
"data": [...],
"meta": {
"total": 150,
"limit": 50,
"offset": 0
}
}
| Parameter | Description | Default |
|---|---|---|
limit | Max items per page | 50 (max 200) |
offset | Skip N items | 0 |
property-id | Filter by property (transactions) | — |
category | Filter by account code (transactions) | — |
from-date | Start date filter (YYYY-MM-DD) | — |
to-date | End date filter (YYYY-MM-DD) | — |
owner_uid | Client UID (CPA keys only) | own account |
Transactions use Perch account codes for categorization:
| Code | Name | Type |
|---|---|---|
401 | Rental Income | Income |
402 | Platform Fees | Income |
601 | Cleaning | Expense |
602 | Supplies | Expense |
603 | Utilities | Expense |
604 | Insurance | Expense |
605 | Repairs & Maintenance | Expense |
606 | Property Management | Expense |
607 | Professional Fees | Expense |
608 | Software & Subscriptions | Expense |
609 | HOA Dues | Expense |
701 | Property Taxes | Tax |
702 | Occupancy Taxes | Tax |
801 | Mortgage Payment | Mortgage |
301 | Personal/Owner Draw | Holding |
302 | Unallocated | Holding |
Receive real-time notifications when data changes in Perch. Webhooks are signed with HMAC-SHA256 so you can verify authenticity.
curl -X POST \
-H "Authorization: Bearer pk_user_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"My Integration","url":"https://example.com/webhook","events":["transaction.created","property.created"]}' \
https://api.getperch.ai/v1/webhooks
The response includes a signing-secret — save it, it's shown only once.
| Event | Triggered When |
|---|---|
property.created | New property added |
property.updated | Property details changed |
property.deleted | Property removed |
transaction.created | New transaction |
transaction.updated | Transaction modified |
transaction.categorized | Category assigned |
transaction.deleted | Transaction removed |
booking.created | New booking |
booking.updated | Booking modified |
booking.deleted | Booking removed |
bank.synced | Bank feed sync completed |
report.generated | Report refreshed |
rule.created | New categorization rule |
rule.deleted | Rule removed |
hours.logged | Participation hours logged |
POST https://your-endpoint.com/webhook
Headers:
Content-Type: application/json
X-Perch-Signature: t=1712345678,v1=abc123def456...
X-Perch-Event: transaction.created
X-Perch-Timestamp: 1712345678
Body:
{
"id": "txn-abc123",
"data": { ... }
}
To verify a webhook is from Perch:
t=) and signature (v1=) from X-Perch-Signaturetimestamp + "." + raw_bodyHMAC-SHA256(signing_secret, signed_content)v1= value# Python example
import hmac, hashlib
def verify_signature(payload, signature_header, secret):
parts = dict(p.split('=', 1) for p in signature_header.split(','))
timestamp = parts['t']
expected = parts['v1']
signed = f"{timestamp}.{payload}"
computed = hmac.new(
secret.encode(), signed.encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed, expected)
The API is rate-limited per user:
Rate-limited responses return HTTP 429 with a Retry-After header.
Questions? Email peter@getperch.ai or ask the Perch AI agent in the app.