Move-outs API
A move-out is the record Rhino opens when a resident vacates a unit. You open one through this API when a resident moves out, and Rhino tracks refund/consent/statement steps against it as they ship.
This is an early release. Today the API covers opening a move-out and reading it back; consent, statement submission, and payout are not live yet and are not documented here until they are. See move_out.initiated for the corresponding webhook.
See Authentication & Environments for base URLs and request signing.
Open a move-out
POST /partners/{owner_slug}/move_outs
Content-Type: application/json
Unlike the prospect and property endpoints, the body is not wrapped in a named key — send the move-out's own fields at the top level:
{
"external_id": "your-move-out-123",
"move_out_date": "2026-09-30",
"property": {
"external_id": "your-property-1",
"address_line_one": "123 Main St",
"address_city": "Chicago",
"address_state": "IL",
"address_zip": "60601"
},
"unit": {
"external_id": "your-unit-1",
"name": "4B"
},
"residents": [
{
"role": "primary",
"name": "Jordan Rivera",
"email": "renter@example.com",
"external_id": "your-resident-1"
}
]
}
external_id is the idempotency key, unique per property owner. Re-POSTing the same external_id returns the existing move-out unchanged — it does not update it and does not create a duplicate. refund_amount_cents is omitted here deliberately: send it only once the refund amount is final, since its presence is what tells Rhino the statement is done.
Both a create and a re-post return 200-shaped bodies with a status_code field: 201 when the move-out was created, 200 when an existing one was returned. Read status_code rather than the HTTP status if you need to tell them apart — the HTTP status matches it in both cases.
Fetch a move-out
GET /partners/{owner_slug}/move_outs/{id}
Returns the same move-out object. Webhooks are the primary channel for status changes; use this to reconcile if you are not subscribed, or to poll after creation.
{id} is the numeric move_out_id from the create response — see the note on IDs below.
Request fields
| Field | Notes |
|---|---|
external_id | Your identifier for the move-out. Required, unique per property owner. |
move_out_date | YYYY-MM-DD. Required. |
property | Object with address_line_one, address_city, address_state, address_zip (all required) and an optional external_id. Stored as sent — see the note below. |
unit | Optional object with external_id and name. |
residents | Required, at least one. Each entry needs role (primary or co_resident) and name; email and external_id are optional. |
refund_amount_cents | Optional. Integer cents. Send only when the refund amount is final. |
The property address is stored exactly as sent, not derived from any Rhino property record. Most departing residents predate any integration Rhino has with your system, so a move-out stands on its own — nothing here requires the property, unit, or residents to already exist in Rhino.
Response
{
"status_code": 201,
"move_out": {
"move_out_id": 1042,
"external_id": "your-move-out-123",
"status": "initiated",
"move_out_date": "2026-09-30",
"refund_amount_cents": null,
"property": {
"external_id": "your-property-1",
"address_line_one": "123 Main St",
"address_city": "Chicago",
"address_state": "IL",
"address_zip": "60601"
},
"unit": {
"external_id": "your-unit-1",
"name": "4B"
},
"residents": [
{
"role": "primary",
"name": "Jordan Rivera",
"email": "renter@example.com",
"external_id": "your-resident-1"
}
]
}
}
Response fields
| Field | Description |
|---|---|
move_out_id | Rhino's numeric ID for the move-out |
status | initiated today. More values arrive as later milestones (consent, statement, payout) ship. |
refund_amount_cents | null until the statement is final |
Note on IDs: unlike prospects (tpp_…) and policies (policy_…), a move-out's ID is a plain integer, not a prefixed string. The same move_out_id appears in the create/fetch response and in the move_out.initiated webhook payload.
Errors
{
"status_code": 422,
"error": "Move-out invalid.",
"move_out": {
"external_id": "can't be blank",
"residents": "must include at least one resident"
}
}
| Status | Meaning |
|---|---|
401 | Request signature missing, malformed, or older than five minutes |
403 | Caller not granted access to this property owner |
404 | Unknown owner_slug, or the move-out does not exist — including one that exists under a different owner |
422 | Validation failure — see the move_out object for field-level detail |
Next steps
- Webhooks Overview — reacting to
move_out.initiatedrather than polling - Event Reference — the
move_out.initiatedpayload