Skip to main content
Developers

API Documentation

Integrate Rentari.ai's property intelligence engine directly into your enterprise software, custom dashboards, or automated workflows.

AI proposes the best matching section. You decide if it answers your question.

Getting Started

Every Rentari.ai API request talks to https://www.rentari.ai/api/v1/external over HTTPS, sends and receives JSON, and is scoped to a single landlord portfolio. Three steps to make your first call:

  1. 1

    Generate an API key

    Open the Developer dashboard, submit a short access request, and once approved click "Create key". Test keys start with sk_test_, live keys with sk_live_. Store the key in your secret manager. We never show it again.

  2. 2

    Send the bearer header

    Add Authorization: Bearer <your_key> to every request. Missing or malformed headers return HTTP 401.

  3. 3

    Make a test call

    Hit GET /api/v1/external/properties with a test key. It returns the demo portfolio, so you can integrate before any real data exists.

Authentication

The Rentari.ai API uses API keys to authenticate requests. You can view and manage your API keys in the Landlord Settings Dashboard. Your API keys carry many privileges, so be sure to keep them secure!

curl https://www.rentari.ai/api/v1/external/properties \
  -H "Authorization: Bearer sk_live_your_api_key_here"

List Properties

Returns a paginated list of all properties within your portfolio. The properties are returned sorted by creation date, with the most recently created properties appearing first.

GET /api/v1/external/properties
curl https://www.rentari.ai/api/v1/external/properties?limit=20 \
  -H "Authorization: Bearer sk_live_your_api_key_here"
Sample Response
{
  "object": "list",
  "data": [
    {
      "id": "prop_8x9a2",
      "street_address": "123 Smart Way",
      "city": "Creve Coeur",
      "state": "MO",
      "unit_count": 4
    }
  ]
}

Generate Lease

Dynamically generate a state-specific lease agreement using our AI Legal Engine. Accepts the property ID and tenant details to return a customized, ESIGN-ready PDF document URL.

POST /api/v1/external/leases/generate
curl -X POST https://www.rentari.ai/api/v1/external/leases/generate \
  -H "Authorization: Bearer sk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "property_id": "prop_8x9a2",
    "tenant_id": "tnt_12fa7",
    "start_date": "2026-06-01",
    "monthly_rent": 1850
  }'
Sample Response
{
  "id": "lease_4q1z8",
  "status": "draft",
  "document_url": "https://cdn.Rentari.ai/leases/lease_4q1z8.pdf",
  "esign_url": "https://www.rentari.ai/sign/lease_4q1z8",
  "expires_at": "2026-06-08T00:00:00Z"
}

Webhooks

Subscribe to real-time events to keep your internal CRM or accounting software perfectly synced with Rentari.ai. Endpoints must be HTTPS and return a 200 status code quickly.

lease.signed

Fired when all parties have securely e-signed an agreement.

payment.succeeded

Fired when a rent ACH or Credit Card payment successfully clears.

maintenance.created

Fired when a tenant submits a new AI-triaged repair ticket.

Webhook Signing

Every webhook delivery includes an X-Rentari.ai-Signature header. Verify it before trusting the payload. The signature is the hex HMAC-SHA256 of timestamp.body using your endpoint signing secret (shown once when you create the endpoint). Reject requests older than 5 minutes to defeat replay attacks.

import hmac, hashlib, time

def verify(secret, raw_body, header):
    ts, sig = header.split(",")
    ts = ts.split("=")[1]
    sig = sig.split("=")[1]
    if abs(time.time() - int(ts)) > 300:
        raise ValueError("stale webhook")
    expected = hmac.new(
        secret.encode(), f"{ts}.{raw_body}".encode(), hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, sig):
        raise ValueError("bad signature")

Rentari.ai retries failed deliveries with exponential backoff for 24 hours. Return any 2xx to acknowledge.

Errors

Rentari.ai uses standard HTTP status codes. All error responses share the same envelope so you can write one handler:

Error Envelope
{
  "error": {
    "type": "validation_error",
    "code": "invalid_field",
    "message": "monthly_rent must be a positive number.",
    "param": "monthly_rent",
    "request_id": "req_8x9a2b1c"
  }
}
StatusTypeWhen you'll see it
400validation_errorBody or query failed schema validation. Check param.
401authentication_errorMissing, malformed, or revoked API key.
403permission_errorKey is valid but lacks the required scope or plan tier.
404not_foundResource id does not exist in your portfolio.
409conflictIdempotency replay with a different body, or stale write.
429rate_limit_exceededBack off, then retry after the Retry-After header.
5xxapi_errorOur problem. Safe to retry with exponential backoff.

Always log request_id. Our support team can find any request by id within 90 days.

Rate Limits

Limits are per API key, measured over a rolling 60-second window. Every response includes the headers below so you can implement adaptive backoff:

Starter

60 req/min

Burst up to 120, then throttled.

Pro

600 req/min

Burst up to 1,200.

Prime

3,000 req/min

Custom ceilings on request.

Response Headers
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 412
X-RateLimit-Reset: 1717689600
Retry-After: 14

Endpoint Reference

The full surface available today. Every list endpoint follows the pagination contract above; every mutation respects idempotency keys via the Idempotency-Key header.

MethodPathWhat it does
GET/api/v1/external/propertiesList properties in the portfolio.
GET/api/v1/external/properties/{id}Retrieve a single property with units.
GET/api/v1/external/tenantsList tenants in the portfolio.
GET/api/v1/external/leasesList leases with status, dates, and rent.
GET/api/v1/external/maintenance/ticketsList repair tickets, including AI triage category.
GET/api/v1/external/paymentsList rent payments with status and method.
POST/api/v1/external/propertiesCreate a property with a default unit. Needs the write scope.
PATCH/api/v1/external/properties/{id}Update a property address or type. Needs the write scope.
PATCH/api/v1/external/tenants/{id}Update tenant contact details. Needs the write scope.
PATCH/api/v1/external/leases/{id}Update a lease. Changing rent or deposit needs the payments scope.
POST/api/v1/external/maintenance/ticketsOpen a maintenance ticket. Needs the write scope.
PATCH/api/v1/external/maintenance/tickets/{id}Update ticket status, priority, text, or vendor. Needs the write scope.
POST/api/v1/external/webhooks/endpointsRegister a webhook endpoint and receive its signing secret.
GET/api/v1/external/webhooks/endpointsList your registered webhook endpoints.
DELETE/api/v1/external/webhooks/endpoints/{id}Disable a webhook endpoint. Existing history preserved.

Need an endpoint that isn't here yet? Email api@rentari.ai with the use case.

Connect Your Own AI (MCP)

Connect a client that supports remote MCP over Streamable HTTP with a custom Authorization header. Only the portfolio owner can connect an assistant. Start with read-only access; explicitly grant write permissions when needed. OAuth-only connectors are not supported yet.

Server endpoint

POST https://www.rentari.ai/mcp

Transport: Streamable HTTP (JSON-RPC 2.0). Authenticate with Authorization: Bearer sk_live_..., exactly as with the REST API.

Setting it up

  1. Open your AI connections settings, request access, and create an API key after approval.
  2. Pick what the key is allowed to do. Read only is the safe default for an assistant.
  3. Copy the key. It is shown once.
  4. Add the server to your assistant. In Cursor, that means a .cursor/mcp.json entry:
{
  "mcpServers": {
    "rentari": {
      "url": "https://www.rentari.ai/mcp",
      "headers": {
        "Authorization": "Bearer sk_live_YOUR_KEY_HERE"
      }
    }
  }
}

Permissions

Every key carries scopes, and the assistant can never exceed them. Choose the narrowest scope that does the job.

ScopeAllows
readPull properties, tenants, leases, maintenance tickets, and payments. Cannot change anything.
writeAlso update properties, tenants, leases, and maintenance tickets.
paymentsAlso change a lease's rent or security deposit, which changes what a tenant is billed.

Test (sandbox) keys are always read only, no matter which scopes they carry. Revoking a key in the dashboard cuts the assistant off immediately.

Available tools

ToolWhat it doesScope
get_expiring_leasesList active leases ending within the next number of days, with full rental addresses. read
get_rent_balancesList remaining unpaid rent charges due through today. read
list_maintenance_requestsList maintenance requests, optionally filtered by status or unit. read
get_unit_historyRead one unit's leases, maintenance or payment history. read
list_propertiesList properties in the connected landlord's portfolio. read
get_propertyGet one property by id, including its unit_count. read
list_tenantsList tenants in the portfolio. read
list_leasesList leases in the portfolio. read
list_maintenance_ticketsList maintenance tickets in the portfolio. read
list_paymentsList rent-ledger rows in the portfolio: rent charges, deposits and fees. read
get_portfolio_summaryReturn headline counts for the whole portfolio: properties, units, tenants, leases and open maintenance tickets. read
update_propertyUpdate a property's address or type. write
update_tenantUpdate a tenant's contact details. write
create_maintenance_ticketOpen a new maintenance ticket. write
update_maintenance_ticketUpdate a maintenance ticket's status, priority, text or vendor. write
update_leaseUpdate a lease. Changing rent or the deposit also needs the payments permission.write

Preview before changing

Every write tool accepts dry_run. With dry_run: true the server validates the change and returns exactly what the record would look like, without saving. The server instructs assistants to preview first and ask for approval. The client controls that approval flow: omitting dry_run or setting it to false saves immediately when the key has write access.

{
  "name": "update_maintenance_ticket",
  "arguments": {
    "ticket_id": "abc123",
    "status": "completed",
    "dry_run": true
  }
}

Limits

MCP calls count against the same per-key rate limits as the REST API, and responses carry the same X-RateLimit-* headers. A single request may carry a batch of up to 20 messages, and each message in the batch counts separately. Assistants tend to be chattier than hand-written integrations, so watch the remaining-call header if you are on the free tier.