API Reference
Rentalot provides a REST API for programmatic access to your account. Use it to sync properties from your PMS, build custom integrations, connect CRM tools, or let AI bots manage your rental operations.
Base URL
The API base URL is the configured server origin with /api/v1 appended:
https://rentalot.ai/api/v1Free Trial access is available on the production origin while the account trial is active. Use https://rentalot.ai/api/v1 by default; an optional local development server can use http://localhost:3000/api/v1. Keep the same origin for web sign-in, Settings/key issuance, dashboard readback, and API requests.
Authentication
All API requests require an API key passed in the Authorization header:
Authorization: Bearer your_api_key_hereGenerate and manage API keys from Settings > API Keys in your dashboard. See Authentication for details.
Optional first CRM job
This is the smallest useful account-scoped integration check: create a private property and contact, read and update them, verify the same IDs in the web CRM, then revoke the key. It does not publish a listing, upload images, send messages, or run a workflow.
-
Choose the server origin before deriving the API base URL. Use
https://rentalot.aifor paid or Free Trial accounts. For optional local Free Trial testing, use a development server origin such ashttp://localhost:3000.export RENTALOT_API_ORIGIN=https://rentalot.ai # For a Free Trial, use instead: # export RENTALOT_API_ORIGIN=http://localhost:3000Keep this origin for web sign-in, Settings/key issuance, dashboard readback, and every API request.
-
Create an account, verify the email, and sign in at
$RENTALOT_API_ORIGIN. -
Open Settings > API Keys at
$RENTALOT_API_ORIGIN/dash/settings?tab=api-keys, create a key, and save the raw value immediately. It is shown only once. For a local Free Trial, this ishttp://localhost:3000/dash/settings?tab=api-keys. -
Derive the API base URL only after selecting the origin:
export RENTALOT_API_KEY=ra_your_key export RENTALOT_API_BASE_URL="$RENTALOT_API_ORIGIN/api/v1"If you change
RENTALOT_API_ORIGIN, deriveRENTALOT_API_BASE_URLagain before making requests. Do not mix a local trial key with the production origin, or vice versa. -
Create a private property with the canonical required fields. Do not include images or the development-only
propertyTypefield in the trial path:property_json=$(curl -sS "$RENTALOT_API_BASE_URL/properties" \ -H "Authorization: Bearer $RENTALOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Example Private Studio", "address": "123 Example Street", "city": "Austin", "state": "TX", "zip": "78701", "monthlyRent": 1800, "bedrooms": 0, "bathrooms": 1, "features": ["hardwood floors"], "isPublic": false }') PROPERTY_ID=$(printf '%s' "$property_json" | jq -r '.data.id') -
Create a contact with an email or phone, then save its ID:
contact_json=$(curl -sS "$RENTALOT_API_BASE_URL/contacts" \ -H "Authorization: Bearer $RENTALOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Ada Lovelace", "email": "ada@example.com", "role": "prospect", "source": "api" }') CONTACT_ID=$(printf '%s' "$contact_json" | jq -r '.data.id') -
Read both records and update only canonical safe fields:
curl -sS "$RENTALOT_API_BASE_URL/properties/$PROPERTY_ID" \ -H "Authorization: Bearer $RENTALOT_API_KEY" curl -sS "$RENTALOT_API_BASE_URL/contacts/$CONTACT_ID" \ -H "Authorization: Bearer $RENTALOT_API_KEY" curl -sS -X PATCH "$RENTALOT_API_BASE_URL/properties/$PROPERTY_ID" \ -H "Authorization: Bearer $RENTALOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"Example Private Studio Updated","monthlyRent":1900}' curl -sS -X PATCH "$RENTALOT_API_BASE_URL/contacts/$CONTACT_ID" \ -H "Authorization: Bearer $RENTALOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channelPreference":"email"}' -
While signed in to the same account at
$RENTALOT_API_ORIGIN, open$RENTALOT_API_ORIGIN/dash/properties/$PROPERTY_IDand$RENTALOT_API_ORIGIN/dash/contacts/$CONTACT_IDand confirm the dashboard shows the same IDs and updated values. For a local Free Trial, these resolve tohttp://localhost:3000/dash/properties/$PROPERTY_IDandhttp://localhost:3000/dash/contacts/$CONTACT_ID. -
Revoke the key at
$RENTALOT_API_ORIGIN/dash/settings?tab=api-keys. A subsequent request with that key must return401 Unauthorized.
For an MCP-shaped version of this job, use the MCP setup guide. The current CLI can read the same IDs, but its property and contact write flags are drifted from the canonical API fields, so do not use CLI writes for this first job. See the CLI guide.
Endpoints
Properties
| Method | Endpoint | Description |
|---|---|---|
GET | /properties | List all properties |
POST | /properties | Create a property |
POST | /properties/bulk | Bulk create properties (async, returns jobId) |
GET | /properties/bulk/:jobId | Poll a bulk-create job |
GET | /properties/:id | Get a property |
PATCH | /properties/:id | Update a property |
DELETE | /properties/:id | Delete a property (soft-delete) |
Property Images
| Method | Endpoint | Description |
|---|---|---|
GET | /properties/:id/images | List images for a property |
POST | /properties/:id/images/presign | Get a presigned upload URL |
POST | /properties/:id/images/confirm | Confirm an uploaded image |
POST | /properties/:id/images/presign-batch | Get multiple presigned URLs |
POST | /properties/:id/images/confirm-batch | Confirm multiple uploads |
POST | /properties/:id/images/import | Import images from URLs (async) |
GET | /properties/:id/images/import/:jobId | Poll an import job |
DELETE | /properties/:id/images | Delete images by ID (batch body) |
PATCH | /properties/:id/images/reorder | Reorder images |
Contacts
| Method | Endpoint | Description |
|---|---|---|
GET | /contacts | List all contacts |
POST | /contacts | Create a contact |
GET | /contacts/:id | Get a contact |
PATCH | /contacts/:id | Update a contact |
DELETE | /contacts/:id | Delete a contact (soft-delete) |
Contacts are also created automatically when prospects interact with your workflows.
Showings
| Method | Endpoint | Description |
|---|---|---|
GET | /showings | List all showings |
POST | /showings | Schedule a showing |
GET | /showings/:id | Get a showing |
PATCH | /showings/:id | Update a showing |
DELETE | /showings/:id | Cancel a showing |
GET | /showings/availability | Check available time slots |
Conversations
| Method | Endpoint | Description |
|---|---|---|
GET | /conversations | List all conversations |
GET | /conversations/:id/messages | Get messages in a conversation |
GET | /conversations/search | Search across message content |
Read-only access for CRM sync and reporting.
Events
| Method | Endpoint | Description |
|---|---|---|
GET | /events | List all calendar events |
Read-only view of your full calendar (showings, synced Google Calendar events, Cal.com events).
Workflows
| Method | Endpoint | Description |
|---|---|---|
GET | /workflows | List workflow templates |
GET | /workflows/:id | Get a template |
GET | /workflows/runs | List workflow runs |
POST | /workflows/runs | Trigger a workflow run |
GET | /workflows/runs/:id | Get a run |
Messages
| Method | Endpoint | Description |
|---|---|---|
POST | /messages | Send a message to a contact |
Drafts
| Method | Endpoint | Description |
|---|---|---|
GET | /drafts | List draft messages |
POST | /drafts | Create a draft |
GET | /drafts/:id | Get a draft |
PATCH | /drafts/:id | Update a draft |
DELETE | /drafts/:id | Delete a draft |
POST | /drafts/:id/send | Send a draft |
Follow-ups
| Method | Endpoint | Description |
|---|---|---|
GET | /followups | List scheduled follow-ups |
POST | /followups | Schedule a follow-up |
GET | /followups/:id | Get a follow-up |
DELETE | /followups/:id | Cancel a follow-up |
Sessions (Pre-Screening)
| Method | Endpoint | Description |
|---|---|---|
GET | /sessions | List pre-screening sessions |
GET | /sessions/:id | Get a session |
PATCH | /sessions/:id/review | Approve or deny a session |
View and manage prospect submissions from public chat workflows.
Webhooks
| Method | Endpoint | Description |
|---|---|---|
GET | /webhooks | List webhook subscriptions |
POST | /webhooks | Create a webhook |
GET | /webhooks/:id | Get a webhook |
PATCH | /webhooks/:id | Update a webhook |
DELETE | /webhooks/:id | Delete a webhook |
POST | /webhooks/:id/test | Send a test ping |
POST | /webhooks/:id/rotate-secret | Rotate the signing secret |
Settings
| Method | Endpoint | Description |
|---|---|---|
GET | /settings | Get all agent settings |
PATCH | /settings | Update agent settings |
GET | /settings/followups | Get follow-up settings |
PATCH | /settings/followups | Update follow-up settings |
Idempotency
POST endpoints that support idempotency accept an optional Idempotency-Key header. If a completed response for the same key and request body exists within 24 hours, you’ll get the cached response back with an X-Idempotent-Replayed: true header. This completion cache does not serialize concurrent first attempts, so it is not an exactly-once guarantee when two requests arrive before either response is stored.
Rate-limit accounting is charge-on-attempt. A failed request can consume quota, and replaying a cached response does not refund quota. Use idempotency keys for sequential retries, and do not rely on them to deduplicate concurrent first attempts.
Idempotency-Key: your-unique-key-hereAccess by Plan
| Plan | API Access | Details |
|---|---|---|
| Free Trial | Core CRUD | Private, image-free properties and contacts only while the account trial is active. |
| Starter | Read-only | GET on the supported API resources. Write operations are not included in Starter API authority. |
| Pro | Paid full authority | Read and write access to the paid API surface, including property/contact writes and webhooks, subject to endpoint limits. |
| Scale | Paid full authority plus priority limits | Pro write authority with higher limits and the Scale priority API feature. |
The API key determines the account and tier. Do not infer API write authority from a web CRM or management-chat control.
Surface and tier boundaries
| Surface | Reads | Writes and current boundary |
|---|---|---|
| Web CRM | Account-owned property/contact, conversation, calendar, workflow, and other dashboard reads | Account-owned dashboard mutations; this is the source of truth for same-record readback in the first job. |
| Management chat | Property/contact/conversation/calendar/workflow tools | Account-scoped writes with management limits. Destructive or externally consequential operations may return a confirmation preview. This interactive confirmation is not inherited by API-key clients. |
| v1 API | Account-owned resources through Bearer API keys | Starter is read-only. Pro/Scale have paid write authority. Free Trial writes are limited to private image-free properties and contacts while the account trial is active. |
| Rentalot CLI | properties list/get and contacts list/get are usable reads | Current property/contact write payloads drift from the API (name/type/rent versus canonical fields). Use MCP or direct API for the first write job until the sibling client sync lands. |
| Rentalot MCP | Registered list/get tools follow the v1 API | Canonical property/contact tool inputs are usable with an eligible key, but omit drifted title/status variants from the first job and include email or phone for contact creation. Other registered tools remain tier and endpoint restricted. |
Each endpoint page in this reference documents its request fields and responses. For client-specific coverage, see MCP Server and CLI.
Rate Limits
Paid-tier rate limits are per API key and vary by plan. Trial limits are durable and account-wide across all active keys:
| Plan | Global RPM | Daily Requests |
|---|---|---|
| Free Trial | 20/min per account | 200/day, 700/trial |
| Starter | 30/min | 5,000/day |
| Pro | 120/min | 50,000/day |
| Scale | 600/min | 500,000/day |
For the trial, properties and contacts each allow 10 reads/minute, 5 writes/minute, 20 writes/day, and 50 writes over the trial lifetime. Trial list pages are capped at 20 items. Trial property mutations are private and image-free, and do not trigger geocoding or outbound webhook/notification side effects. Image endpoints, image URL imports, bulk operations, messages, workflows, showings, webhooks, provider integrations, and AI/outbound actions are not part of the trial surface.
Write operations on paid tiers have additional per-resource daily and monthly caps. See your plan details for specifics.
Rate limit headers are included in every response:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1707667200
X-RateLimit-Resource: properties
Retry-After: 3 (429 responses only)Daily trial total and resource-write exhaustion returns Retry-After seconds until the next UTC midnight. Trial lifetime exhaustion has no timed retry: upgrade to continue, and rotating keys does not reset it. A transient trial usage-store failure fails closed with a finite five-second retry interval.
Pagination
All list endpoints return paginated results:
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 142,
"totalPages": 8
}
}Page size is capped by your plan tier (Free Trial: 20, Starter: 50, Pro: 100, Scale: 200).
Trial signup and account controls
Free Trial API access is a released, bounded entitlement, not a production signup-abuse control. Signup requires email verification. Production Better Auth configuration applies a 5/minute sign-up rule and a 100/minute general rule; development disables Better Auth’s built-in limiter. The current account schema/control plane has no account-suspension authority and no cross-account identity/Sybil prevention guarantee.
Errors
Errors follow RFC 9457 Problem Details . Responses use Content-Type: application/problem+json:
{
"type": "https://rentalot.ai/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Property not found"
}Validation errors include a per-field errors array:
{
"type": "https://rentalot.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "Request validation failed",
"errors": [
{ "field": "monthlyRent", "message": "Expected number, received string" }
]
}| Status | type (suffix of https://rentalot.ai/problems/) | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | Plan doesn’t allow this operation |
| 404 | not-found | Resource not found |
| 409 | conflict | Resource already exists |
| 410 | gone | Resource has expired |
| 422 | validation-error / unprocessable-entity | Invalid request body, parameters, or business-rule violation |
| 429 | rate-limited | Rate limit exceeded — check Retry-After header |
| 500 | internal-error | Server error — safe to retry with backoff |
Developer Tools
MCP Server
Connect an AI assistant with the Rentalot MCP server . The package registers 65 tools, but current API tier restrictions and client contract drift still apply. The MCP setup guide includes the correct RENTALOT_API_KEY and RENTALOT_BASE_URL configuration, the private first CRM job, and current limitations.
The MCP client’s RENTALOT_BASE_URL is the server origin, such as https://rentalot.ai or a local development origin. Do not append /api/v1 to that variable.
claude mcp add rentalot \
-e RENTALOT_API_KEY=ra_your_key \
-e RENTALOT_BASE_URL=https://rentalot.ai \
-- npx -y @rentalot/mcp-serverCLI
Install the Rentalot CLI for terminal reads and the current partial resource surface:
go install github.com/Rentalot-ai/rentalot-cli/cmd/rentalot@latest
rentalot config set api_key ra_your_key
rentalot config set base_url https://rentalot.ai
rentalot --helpbase_url and RENTALOT_BASE_URL also use the server origin, not /api/v1. The CLI guide documents why its current property/contact write flags are not a canonical write path.
OpenAPI Spec
A machine-readable OpenAPI 3.0 spec is available at:
GET /api/v1/openapi.jsonUse it to auto-generate client libraries in any language.