REST API reference

DoorLoop API

14 endpoints for DoorLoop. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/doorloop
Connects with
Your own DoorLoop account (a user who can manage leases, payments and communications)
Integration page
DoorLoop
DoorLoop Endpoints
Endpoint Access Description
list_properties read Your properties with address, type and unit count.
list_units read Units with property, rent and whether each is occupied or vacant.
list_tenants read Tenants with email, phone, unit and current lease.
list_leases read Leases with unit, tenants, rent, start and end dates and balance due.
get_lease_transactions read Charges, payments and credits on a lease, oldest first, with the running balance.
list_tasks read Tasks and work orders with status, due date, property and assignee.
list_communications read The Communications Log: announcements and messages sent, with channel and delivery status.
create_tenant write Add a tenant contact, ready to put on a lease. Sends nothing.
create_task write New task or work order for a property or unit.
create_lease write New lease on a unit with tenants, term, monthly rent and security deposit.
post_lease_charge write One-time charge on a lease, such as a late fee. It shows on the tenant's balance.
record_lease_payment write Record a payment received outside online payments and apply it to open charges.
issue_lease_credit write Credit a lease, such as a rent concession, lowering the tenant's balance.
send_announcement write Announcement to tenants by email, text or tenant portal. Texts use announcement credits.

POST https://cotlet.dev/api/v1/doorloop/list_properties

Returns the properties in your DoorLoop account, with address and number of units. Search matches the property name or address. Use the property_id of each item in the other tools.

Parameters

Parameters: list_properties
NameTypeDescription
search string Match on property name or address.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_properties \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_properties")
Node.js
const result = await cotlet.call('doorloop', 'list_properties');
CLI
cotlet call doorloop list_properties

Example response

{
  "properties": [
    {
      "property_id": "pr_3a91c7",
      "name": "Maple Court",
      "address": "120 Maple St, Springfield",
      "type": "Multi-family",
      "units": 12
    }
  ],
  "next_cursor": null
}

List units

read

POST https://cotlet.dev/api/v1/doorloop/list_units

Returns units with the property they belong to and their occupancy. Filter by property or by occupied or vacant. Use unit_id from here in create_lease.

Parameters

Parameters: list_units
NameTypeDescription
property_id string Only this property. Property ID from list_properties.
status enum all, occupied or vacant. Default: all.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_units \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_units")
Node.js
const result = await cotlet.call('doorloop', 'list_units');
CLI
cotlet call doorloop list_units

Example response

{
  "units": [
    {
      "unit_id": "un_5b20d4",
      "property": "Maple Court",
      "name": "Unit 4",
      "status": "vacant",
      "market_rent": "1600.00"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/doorloop/list_tenants

Returns tenants with contact details and the lease they are on. Search matches name, email or phone. Use tenant_id from here in create_lease.

Parameters

Parameters: list_tenants
NameTypeDescription
search string Match on name, email or phone.
property_id string Only this property. Property ID from list_properties.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_tenants \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_tenants")
Node.js
const result = await cotlet.call('doorloop', 'list_tenants');
CLI
cotlet call doorloop list_tenants

Example response

{
  "tenants": [
    {
      "tenant_id": "tn_91c0e7",
      "name": "Dana Reed",
      "email": "dana@example.com",
      "phone": "+15555550123",
      "unit": "Unit 4",
      "lease_id": null
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/doorloop/list_leases

Returns leases with the unit, the tenants on them, monthly rent, dates and the balance due. Filter by status, by end date or by property. Use lease_id from here in the other lease tools. Search matches unit or tenant name.

Parameters

Parameters: list_leases
NameTypeDescription
search string Match on unit or tenant name.
status enum active or ended. Default: active.
ends_before date Only leases ending on or before this date.
property_id string Only this property. Property ID from list_properties.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_leases \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_leases")
Node.js
const result = await cotlet.call('doorloop', 'list_leases');
CLI
cotlet call doorloop list_leases

Example response

{
  "leases": [
    {
      "lease_id": "ls_64f1a9c2",
      "unit": "Unit 2B",
      "property": "Maple Court",
      "tenants": [
        "Marcus Hale"
      ],
      "rent": "1450.00",
      "start_date": "2026-01-01",
      "end_date": "2026-12-31",
      "balance_due": "1450.00"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/doorloop/get_lease_transactions

Returns the ledger of one lease, oldest first: charges, payments and credits, each with a running balance. Use it to see whether a rent charge is still open before you add a fee or record a payment.

Parameters

Parameters: get_lease_transactions
NameTypeDescription
lease_id required string Lease ID from list_leases.
from date Start date. Default: lease start.
to date End date. Default: today.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/get_lease_transactions \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id":"lease_8c41d2"}'
Python
result = client.call("doorloop", "get_lease_transactions", {"lease_id":"lease_8c41d2"})
Node.js
const result = await cotlet.call('doorloop', 'get_lease_transactions', {"lease_id":"lease_8c41d2"});
CLI
cotlet call doorloop get_lease_transactions --data '{"lease_id":"lease_8c41d2"}'

Example response

{
  "lease_id": "ls_64f1a9c2",
  "transactions": [
    {
      "type": "charge",
      "date": "2026-10-01",
      "description": "Rent October 2026",
      "amount": "1450.00",
      "balance": "1450.00"
    }
  ],
  "balance_due": "1450.00"
}

List tasks

read

POST https://cotlet.dev/api/v1/doorloop/list_tasks

Returns tasks and work orders, filtered by status or property. Each item has its subject, the property or unit it concerns, the due date and who it is assigned to.

Parameters

Parameters: list_tasks
NameTypeDescription
status string Only tasks with this status, as DoorLoop shows it.
property_id string Only this property. Property ID from list_properties.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_tasks \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_tasks")
Node.js
const result = await cotlet.call('doorloop', 'list_tasks');
CLI
cotlet call doorloop list_tasks

Example response

{
  "tasks": [
    {
      "task_id": "tk_20c8",
      "subject": "Fix hallway light",
      "property": "Maple Court",
      "unit": null,
      "status": "open",
      "due_date": "2026-10-15",
      "assignee": "Sam Ortiz"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/doorloop/list_communications

Returns entries from the Communications Log, newest first, with the channel, subject and delivery status. Use it after send_announcement to see who the announcement reached.

Parameters

Parameters: list_communications
NameTypeDescription
since datetime Only entries sent after this time.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/list_communications \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("doorloop", "list_communications")
Node.js
const result = await cotlet.call('doorloop', 'list_communications');
CLI
cotlet call doorloop list_communications

Example response

{
  "communications": [
    {
      "communication_id": "cm_77f0",
      "subject": "Water shutoff Thursday",
      "channel": "email",
      "sent_at": "2026-10-11T09:02:00Z",
      "delivery": "delivered",
      "recipients": 12
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/doorloop/create_tenant

Adds one tenant contact. It sends nothing to the tenant and attaches no charge. It runs without asking first, because it reaches no one and the contact can be deleted in DoorLoop.

Parameters

Parameters: create_tenant
NameTypeDescription
first_name required string First name.
last_name required string Last name.
email string Email address.
phone string Phone number, E.164.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/create_tenant \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"first name","last_name":"last name"}'
Python
result = client.call("doorloop", "create_tenant", {"first_name":"first name","last_name":"last name"})
Node.js
const result = await cotlet.call('doorloop', 'create_tenant', {"first_name":"first name","last_name":"last name"});
CLI
cotlet call doorloop create_tenant --data '{"first_name":"first name","last_name":"last name"}'

Example response

{
  "tenant_id": "tn_91c0e7",
  "name": "Dana Reed",
  "email": "dana@example.com",
  "status": "created"
}

Create task

write

POST https://cotlet.dev/api/v1/doorloop/create_task

Creates a task or work order with a subject, optional property or unit and a due date. It does not message anyone by itself. It runs without asking first, because it reaches no tenant and the task can be removed in DoorLoop.

Parameters

Parameters: create_task
NameTypeDescription
subject required string Short title.
description string Details for whoever does the work.
property_id string Only this property. Property ID from list_properties.
unit_id string Unit it concerns.
due_date date Due date.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/create_task \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"subject"}'
Python
result = client.call("doorloop", "create_task", {"subject":"subject"})
Node.js
const result = await cotlet.call('doorloop', 'create_task', {"subject":"subject"});
CLI
cotlet call doorloop create_task --data '{"subject":"subject"}'

Example response

{
  "task_id": "tk_20c9",
  "subject": "Replace smoke detector, Unit 2B",
  "property": "Maple Court",
  "due_date": "2026-10-18",
  "status": "created"
}

Create lease

write Confirm

POST https://cotlet.dev/api/v1/doorloop/create_lease

Creates a lease on one unit in a single step: tenants, term, recurring rent with its due day and an optional security deposit. Leave end_date empty for a month-to-month lease. The lease creates charges on the ledger. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_lease
NameTypeDescription
unit_id required string Unit ID from list_units.
tenant_ids required string[] Tenant IDs from list_tenants or create_tenant.
start_date required date First day of the lease.
end_date date Last day. Leave empty for month-to-month.
rent required object amount and due_day of the recurring rent charge.
security_deposit object amount and due_date.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/create_lease \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"unit_id":"un_5b20d4","tenant_ids":["tn_91c0e7"],"start_date":"2026-11-01","end_date":"2027-10-31","rent":{"amount":"1600.00","due_day":1},"security_deposit":{"amount":"1600.00","due_date":"2026-11-01"}}'
Python
result = client.call("doorloop", "create_lease", {"unit_id":"un_5b20d4","tenant_ids":["tn_91c0e7"],"start_date":"2026-11-01","end_date":"2027-10-31","rent":{"amount":"1600.00","due_day":1},"security_deposit":{"amount":"1600.00","due_date":"2026-11-01"}})
Node.js
const result = await cotlet.call('doorloop', 'create_lease', {"unit_id":"un_5b20d4","tenant_ids":["tn_91c0e7"],"start_date":"2026-11-01","end_date":"2027-10-31","rent":{"amount":"1600.00","due_day":1},"security_deposit":{"amount":"1600.00","due_date":"2026-11-01"}});
CLI
cotlet call doorloop create_lease --data '{"unit_id":"un_5b20d4","tenant_ids":["tn_91c0e7"],"start_date":"2026-11-01","end_date":"2027-10-31","rent":{"amount":"1600.00","due_day":1},"security_deposit":{"amount":"1600.00","due_date":"2026-11-01"}}'

Example response

{
  "lease_id": "ls_9e13b5",
  "unit": "Unit 4",
  "tenants": [
    "Dana Reed"
  ],
  "start_date": "2026-11-01",
  "end_date": "2027-10-31",
  "rent": {
    "amount": "1600.00",
    "due_day": 1
  },
  "security_deposit": {
    "amount": "1600.00",
    "due_date": "2026-11-01"
  },
  "status": "created"
}

Post lease charge

write Confirm

POST https://cotlet.dev/api/v1/doorloop/post_lease_charge

Adds one charge to a lease ledger, for example a late fee or a utility bill. It raises the balance due. It does not change your late fee policy. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: post_lease_charge
NameTypeDescription
lease_id required string Lease ID from list_leases.
amount required string Decimal amount, e.g. "50.00".
date required date Charge date.
account required string Income account, as named in your DoorLoop chart of accounts.
memo string Shown on the ledger.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/post_lease_charge \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id":"lease_8c41d2","amount":"50.00","date":"2026-10-01","account":"account"}'
Python
result = client.call("doorloop", "post_lease_charge", {"lease_id":"lease_8c41d2","amount":"50.00","date":"2026-10-01","account":"account"})
Node.js
const result = await cotlet.call('doorloop', 'post_lease_charge', {"lease_id":"lease_8c41d2","amount":"50.00","date":"2026-10-01","account":"account"});
CLI
cotlet call doorloop post_lease_charge --data '{"lease_id":"lease_8c41d2","amount":"50.00","date":"2026-10-01","account":"account"}'

Example response

{
  "charge_id": "ch_41b7",
  "lease_id": "ls_64f1a9c2",
  "amount": "50.00",
  "date": "2026-10-11",
  "account": "Late Fees",
  "balance_due": "1500.00",
  "status": "posted"
}

Record lease payment

write Confirm

POST https://cotlet.dev/api/v1/doorloop/record_lease_payment

Records a payment on a lease, the same as Receive Payment in DoorLoop, and applies it to open charges. The response lists the charges it was applied to and the balance after. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: record_lease_payment
NameTypeDescription
lease_id required string Lease ID from list_leases.
amount required string Decimal amount received.
date required date Date received.
method required string Payment method as DoorLoop lists it, e.g. check or cash.
reference string Check number or other reference.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/record_lease_payment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id":"ls_64f1a9c2","amount":"1450.00","date":"2026-10-11","method":"check","reference":"1042"}'
Python
result = client.call("doorloop", "record_lease_payment", {"lease_id":"ls_64f1a9c2","amount":"1450.00","date":"2026-10-11","method":"check","reference":"1042"})
Node.js
const result = await cotlet.call('doorloop', 'record_lease_payment', {"lease_id":"ls_64f1a9c2","amount":"1450.00","date":"2026-10-11","method":"check","reference":"1042"});
CLI
cotlet call doorloop record_lease_payment --data '{"lease_id":"ls_64f1a9c2","amount":"1450.00","date":"2026-10-11","method":"check","reference":"1042"}'

Example response

{
  "payment_id": "pm_8d2e71b0",
  "lease_id": "ls_64f1a9c2",
  "amount": "1450.00",
  "method": "check",
  "reference": "1042",
  "applied_to": [
    {
      "charge": "Rent October 2026",
      "amount": "1450.00"
    }
  ],
  "balance_due": "0.00"
}

Issue lease credit

write Confirm

POST https://cotlet.dev/api/v1/doorloop/issue_lease_credit

Adds a credit to a lease ledger, which lowers the balance due. Use the memo to record the reason. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: issue_lease_credit
NameTypeDescription
lease_id required string Lease ID from list_leases.
amount required string Decimal amount.
date required date Credit date.
memo string Reason, shown on the ledger.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/issue_lease_credit \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id":"lease_8c41d2","amount":"amount","date":"2026-10-01"}'
Python
result = client.call("doorloop", "issue_lease_credit", {"lease_id":"lease_8c41d2","amount":"amount","date":"2026-10-01"})
Node.js
const result = await cotlet.call('doorloop', 'issue_lease_credit', {"lease_id":"lease_8c41d2","amount":"amount","date":"2026-10-01"});
CLI
cotlet call doorloop issue_lease_credit --data '{"lease_id":"lease_8c41d2","amount":"amount","date":"2026-10-01"}'

Example response

{
  "credit_id": "cr_19a4",
  "lease_id": "ls_64f1a9c2",
  "amount": "100.00",
  "date": "2026-10-11",
  "balance_due": "1350.00",
  "status": "posted"
}

Send announcement

write Confirm

POST https://cotlet.dev/api/v1/doorloop/send_announcement

Sends an announcement to tenants of the full portfolio or of chosen properties. Email and portal posts are free. Text messages use announcement credits (1 per 160 characters) and are capped at 800 characters. Announcements need DoorLoop's Pro or Premium plan. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_announcement
NameTypeDescription
subject required string Announcement title.
body required string Message text.
property_ids string[] Only tenants in these properties. Default: all.
channels required string[] Any of email, text, portal.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/doorloop/send_announcement \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"Water shutoff Thursday","body":"Water will be off Thursday from 9:00 to 12:00 for pipe repairs.","property_ids":["pr_3a91c7"],"channels":["email","text"]}'
Python
result = client.call("doorloop", "send_announcement", {"subject":"Water shutoff Thursday","body":"Water will be off Thursday from 9:00 to 12:00 for pipe repairs.","property_ids":["pr_3a91c7"],"channels":["email","text"]})
Node.js
const result = await cotlet.call('doorloop', 'send_announcement', {"subject":"Water shutoff Thursday","body":"Water will be off Thursday from 9:00 to 12:00 for pipe repairs.","property_ids":["pr_3a91c7"],"channels":["email","text"]});
CLI
cotlet call doorloop send_announcement --data '{"subject":"Water shutoff Thursday","body":"Water will be off Thursday from 9:00 to 12:00 for pipe repairs.","property_ids":["pr_3a91c7"],"channels":["email","text"]}'

Example response

{
  "communication_id": "cm_77f0",
  "subject": "Water shutoff Thursday",
  "channels": [
    "email",
    "text"
  ],
  "recipients": 12,
  "status": "sent"
}