Skip to content

Onboarding a property

Everything in Vespy hangs off a lease: charges, payments, maintenance, and the owner ledger all resolve through it. This is the shortest path from an empty portfolio to a lease that can be billed.

property ──> unit ──┐
├──> lease ──> charges ──> payments
tenant ─────────────┘
Terminal window
curl -X POST https://api.getvespy.com/api/properties \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Elm Street Duplex",
"streetLine1": "412 Elm Street",
"city": "Austin",
"state": "TX",
"postalCode": "78702",
"units": 2,
"occupiedUnits": 0
}'

units and occupiedUnits are the headline counts shown on the portfolio dashboard. They are declared here and maintained by the API as leases come and go — you do not increment them yourself.

Pass ownerIds if the property is owned by someone you already have on file; owner statements and the trust ledger key off that association. To create the first unit in the same request, pass initialUnit.

Terminal window
curl -X POST "https://api.getvespy.com/api/properties/$PROPERTY_ID/units" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"unitNumber": "A",
"bedrooms": 2,
"bathrooms": 1,
"monthlyRentCents": 185000,
"status": "vacant",
"accessInstructions": "Lockbox on the gas meter, code 4417"
}'

monthlyRentCents is the asking rent and is only a default — the lease carries the rent actually charged. accessInstructions is worth filling in now: work orders created on this unit inherit it as their entry instructions.

Terminal window
curl -X POST https://api.getvespy.com/api/tenants \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"fullName": "Dana Reyes",
"email": "dana@example.com",
"phone": "+15125550143"
}'

A tenant record is not a login. To give this person portal access, send a tenant invite after the lease exists — the invite links their account to the tenant record and scopes what they can see.

Terminal window
curl -X POST https://api.getvespy.com/api/leases \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"propertyId": "'"$PROPERTY_ID"'",
"unitId": "'"$UNIT_ID"'",
"tenantId": "'"$TENANT_ID"'",
"startDate": "2026-09-01",
"endDate": "2027-08-31",
"rentCents": 185000,
"rentChargeDay": 1,
"moveInDate": "2026-09-01",
"lateFeeType": "flat",
"lateFeeAmountCents": 7500,
"lateFeeGraceDays": 5
}'

rentChargeDay drives recurring rent generation — set it and monthly rent charges are created for you. Late fee terms are part of the lease rather than a global setting, so they can differ per lease.

Use additionalRecurringCharges for anything billed alongside rent every month, such as parking or pet rent, rather than creating those charges by hand each period.

Terminal window
curl -X POST "https://api.getvespy.com/api/leases/$LEASE_ID/status" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"status":"active"}'

Activating the lease is what flips the unit to occupied and starts rent generation. A lease left in draft bills nothing.